Given an integer n, determine if it is a Lucky Number.
Lucky numbers are identified using a elimination process on the infinite sequence of natural numbers (1, 2, 3, 4, ...):
1. Remove every 2nd number from the sequence.
2. From the remaining sequence, remove every 3rd number.
3. From the remaining sequence, remove every 4th number, and so on...
This continues indefinitely. Return true if n survives the elimination process (is a lucky number). Otherwise, return false.
Input: n = 5
Output: false
Explanation: 5 is not a lucky number as it gets deleted in the second iteration.Input: n = 19
Output: true
Explanation: 19 is a lucky number because it does not get deleted throughout the process.
Table of Content
[Naive Approach] Simulate Elimination - O(n log n) and O(n)
We explicitly simulate the elimination process by generating an array of integers from 1 to n.
In the kth step (starting from 2), we remove every k-th element from our list until the step size k exceeds the remaining length of the list, and then check if n survived.
#include <bits/stdc++.h>
using namespace std;
bool isLucky(int n)
{
// Generate the initial sequence from 1 to n
vector<int> nums(n);
for (int i = 0; i < n; ++i)
{
nums[i] = i + 1;
}
int k = 2;
// Continue eliminating while the step size is valid
while (k <= nums.size())
{
// Use a temporary vector to store surviving numbers
vector<int> next_nums;
for (int i = 0; i < nums.size(); ++i)
{
// Keep the number if its 1-based position
// is NOT a multiple of k
if ((i + 1) % k != 0)
{
next_nums.push_back(nums[i]);
}
}
// Update our main sequence to the newly filtered one
nums = next_nums;
k++;
}
// Check if 'n' survived by searching for it
// in the remaining numbers
return find(nums.begin(), nums.end(), n) != nums.end();
}
int main()
{
int x = 5;
if (isLucky(x))
cout << "true" << endl;
else
cout << "false" << endl;
}
import java.util.ArrayList;
import java.util.List;
public class Main {
public static boolean isLucky(int n)
{
// Generate the initial sequence from 1 to n
List<Integer> nums = new ArrayList<>();
for (int i = 1; i <= n; ++i) {
nums.add(i);
}
int k = 2;
// Continue eliminating while the step size is valid
while (k <= nums.size()) {
// Use a temporary list to store surviving
// numbers
List<Integer> next_nums = new ArrayList<>();
for (int i = 0; i < nums.size(); ++i) {
// Keep the number if its 1-based position
// is NOT a multiple of k
if ((i + 1) % k != 0) {
next_nums.add(nums.get(i));
}
}
// Update our main sequence to the newly
// filtered one
nums = next_nums;
k++;
}
// Check if 'n' survived by searching for it in the
// remaining numbers
return nums.contains(n);
}
public static void main(String[] args)
{
int x = 5;
if (isLucky(x)) {
System.out.println("true");
}
else {
System.out.println("false");
}
}
}
def isLucky(n):
# Generate the initial sequence from 1 to n
nums = list(range(1, n + 1))
k = 2
# Continue eliminating while the step size is valid
while k <= len(nums):
# Use a temporary list to store surviving numbers
next_nums = []
for i in range(len(nums)):
# Keep the number if its 1-based position
# is NOT a multiple of k
if (i + 1) % k != 0:
next_nums.append(nums[i])
# Update our main sequence to the newly filtered one
nums = next_nums
k += 1
# Check if 'n' survived by searching for it in the remaining numbers
return n in nums
if __name__ == "__main__":
x = 5
if isLucky(x):
print("true")
else:
print("false")
using System;
class GfG
{
static bool isLucky(int n)
{
int[] nums = new int[n];
// Create the initial sequence
for (int i = 0; i < n; i++)
nums[i] = i + 1;
int size = n;
int k = 2;
// Remove every k-th element
while (k <= size)
{
int write = 0;
for (int i = 0; i < size; i++)
{
if ((i + 1) % k != 0)
nums[write++] = nums[i];
}
size = write;
k++;
}
// Check whether n survived
for (int i = 0; i < size; i++)
{
if (nums[i] == n)
return true;
}
return false;
}
static void Main()
{
int x = 5;
if (isLucky(x))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
}
}
function isLucky(n)
{
// Generate the initial sequence from 1 to n
let nums = Array.from({length : n}, (_, i) => i + 1);
let k = 2;
// Continue eliminating while the step size is valid
while (k <= nums.length) {
// Use a temporary array to store surviving numbers
let next_nums = [];
for (let i = 0; i < nums.length; ++i) {
// Keep the number if its 1-based position
// is NOT a multiple of k
if ((i + 1) % k != 0) {
next_nums.push(nums[i]);
}
}
// Update our main sequence to the newly filtered
// one
nums = next_nums;
k++;
}
// Check if 'n' survived by searching for it in the
// remaining numbers
return nums.includes(n);
}
// Driver Code
let x = 5;
if (isLucky(x)) {
console.log("true");
}
else {
console.log("false");
}
Output
false
[Expected Approach] Position Tracking - O(sqrt(n)) Time and O(1) Space
We only track the current position of n, which is initially n itself.
At each step k,
- If the position is perfectly divisible by k, n is the element being removed.
- Otherwise, its new position shifts leftward by the number of elements removed before it (n - n / k).
Let's understand with an example:
Say, n=13
We have: Initial position: n, i.e. 13 itself. Sequence : 1,2,3,4,5,6,7,8,9,10,11,12,13
- k = 2 : Removing every second elements. So now the position of 13 will be : n-n/2 = 13-6=7. Sequence : 1,3,5,7,9,11,13.
- k = 3 : Removing n/3 items. Note that n now is n=7. So position of 13 : n-n/3 = 7-7/3 = 7-2 = 5. Sequence = 1,3,7,9,13.
- k = 4 : So next it will be : n-n/4 = 5-5/4 = 4. Sequence = 1,3,7,13.
- k = 5 : Since position of 13 is 4 only, so it will be saved.
Hence return true.
#include <bits/stdc++.h>
using namespace std;
bool isLucky(int n)
{
int counter = 2;
// Loop continues as long as counter <= n
while (counter <= n) {
// If the position is a multiple of counter, it's eliminated
if (n % counter == 0)
return false;
// Calculate next position of input no
n = n - n / counter;
// Increment the step size
counter++;
}
// If we break out of the loop, the number survived
return true;
}
int main()
{
int x = 5;
// Function call
if (isLucky(x))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
public class Main {
public static boolean isLucky(int n) {
int counter = 2;
// Loop continues as long as counter <= n
while (counter <= n) {
// If the position is a multiple of counter, it's eliminated
if (n % counter == 0)
return false;
// Calculate next position of input no
n = n - n / counter;
// Increment the step size
counter++;
}
// If we break out of the loop, the number survived
return true;
}
public static void main(String[] args) {
int x = 5;
// Function call
if (isLucky(x))
System.out.println("true");
else
System.out.println("false");
}
}
def isLucky(n):
counter = 2
# Loop continues as long as counter <= n
while counter <= n:
# If the position is a multiple of counter, it's eliminated
if n % counter == 0:
return False
# Calculate next position of input no
n = n - n // counter
# Increment the step size
counter += 1
# If we break out of the loop, the number survived
return True
if __name__ == "__main__":
x = 5
if isLucky(x):
print('true')
else:
print('false')
using System;
public class Program
{
public static bool isLucky(int n)
{
int counter = 2;
// Loop continues as long as counter <= n
while (counter <= n)
{
// If the position is a multiple of counter, it's eliminated
if (n % counter == 0)
return false;
// Calculate next position of input no
n = n - n / counter;
// Increment the step size
counter++;
}
// If we break out of the loop, the number survived
return true;
}
public static void Main()
{
int x = 5;
if (isLucky(x))
Console.WriteLine("true");
else
Console.WriteLine("false");
}
}
function isLucky(n) {
let counter = 2;
// Loop continues as long as counter <= n
while (counter <= n) {
// If the position is a multiple of counter, it's eliminated
if (n % counter === 0)
return false;
// Calculate next position of input no
n = n - Math.floor(n / counter);
// Increment the step size
counter++;
}
// If we break out of the loop, the number survived
return true;
}
// Driver Code
let x = 5;
if (isLucky(x))
console.log('true');
else
console.log('false');
Output
false