193 Kth Smallest With Only 3, 5, 7 As Factors (Lai)
Find the Kth smallest number s such that s = 3 ^ x * 5 ^ y * 7 ^ z, x > 0 and y > 0 and z > 0, x, y, z are all integers.
Assumptions
- K >= 1
Examples
- the smallest is 3 * 5 * 7 = 105
- the 2nd smallest is 3 ^ 2 * 5 * 7 = 315
- the 3rd smallest is 3 * 5 ^ 2 * 7 = 525
- the 5th smallest is 3 ^ 3 * 5 * 7 = 945
Solution:
public class Solution {
// Method 1: BFS
public long kth(int k) {
// Write your solution here
// Assumptions: K >= 1.
PriorityQueue<Long> minHeap = new PriorityQueue<>(k);
// java 默认最小堆
Set<Long> visited = new HashSet<>();
// we use the actual product value to represent the states
// <x, y, z>, the value is 3^x * 5^y *7^z, and the initial
// state is <1,1,1>.
minHeap.offer(3 * 5 * 7L);
visited.add(3 * 5 * 7L);
while(k > 1){
long current = minHeap.poll();
// for the state <x+1, y, z>, the actual value is *3.
if (!visited.contains(3 * current)){
visited.add(3*current);
minHeap.offer(3*current);
}
// for the state <x, y+1, z>, the actual value is *5.
if (!visited.contains(5*current)){
visited.add(5*current);
minHeap.offer(5 * current);
}
// for the state <x, y, z+1>
if (!visited.contains(5*current)){
visited.add(5*current);
minHeap.offer(5 * current);
}
k--;
}
return minHeap.peek();
}
}
// TC: O(klogk)
// SC: O(k)
public class Solution {
// Method 2: Linear solution using 3 deques
public long kth(int k) {
// Write your solution here
// Assumptinos: k >= 1
long seed = 3 * 5 * 7L;
// use three deques to maintain all the possible values.
// the rule is:
// deque3 only maintains the value of seed * 3^x.
// deque5 only maintains the value of seed * 3^x * 5^y.
// deque7 only maintains the value of seed * 3^x * 5^y * 7^z.
Deque<Long> three = new LinkedList<>();
Deque<Long> five = new LinkedList<>();
Deque<Long> seven = new LinkedList<>();
three.add(seed * 3);
five.add(seed * 5);
seven.add(seed * 7);
long result = seed;
while (k > 1){
// each round, pick the smallest one from th head of the three deques.
// when pushing back the value into the deques, following the rule:
//
// if the smallest number x is from deque3:
// we need to push x*3 to deque3, x*5 to deque5 and x*7 to deque7,
// to maintain the property of the three deques.
//
// if the smallest number x is from deque5:
// we only need to push x*5 to deque5 and x*7 to deque7,
// we do not need to push x*3 again,
// because x*3 has to be already generated before,
// x=3^a*5^b, x*3=3^(a+1)*5^b = 3^(a+1)*5^(b-1)*5,
// and 3^(a+1)*5^(b-1)<x, it means x*3 has to be already
// generatd by 3^(a+1)*5(b-1), and it already in deque5.
// similarly, if the smallest number x is from deque7:
// we only need to push x*7 to deque7.
if (there.peekFirst() < five.peekFirst() && three.peekFirst() < seven.peekFirst()){
result = three.pollFirst();
three.offerLast(result * 3);
five.offerLast(result * 5);
seven.offerLast(result * 7);
} else if (five.peekFirst() < three.peekFirst() && five.peekFirst() < seven.peekFirst()){
result = five.pollFirst();
five.offerLast(result * 5);
seven.offerLast(result * 7);
} else {
result = seven.pollFirst();
seven.offerLast(result * 7);
}
k--;
}
return result;
}
}
// TC: O(k)
// SC: O(k)