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] Brute Force - O(n log n) and O(n)
We can explicitly simulate the elimination process by generating an array of integers from 1 to n. In each step k (starting from 2), we physically 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 << "no" << 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("no");
}
}
}
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("no")
using System;
using System.Collections.Generic;
public class Program {
public static bool isLucky(int n)
{
// Generate the initial sequence from 1 to n
List<int> nums = new List<int>();
for (int i = 1; i <= n; ++i) {
nums.Add(i);
}
int k = 2;
// Continue eliminating while the step size is valid
while (k <= nums.Count) {
// Use a temporary list to store surviving
// numbers
List<int> next_nums = new List<int>();
for (int i = 0; i < nums.Count; ++i) {
// Keep the number if its 1-based position
// is NOT a multiple of k
if ((i + 1) % k != 0) {
next_nums.Add(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.Contains(n);
}
public static void Main()
{
int x = 5;
if (isLucky(x)) {
Console.WriteLine("true");
}
else {
Console.WriteLine("no");
}
}
}
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("no");
}
[Expected Approach] Position Tracking - O(sqrt(n)) Time and O(1) Space
Instead of keeping track of the entire sequence, 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" <<
}
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
5 is not a lucky no.