Question 2 Iterator for Combination
Method 1
和刚才的题目一样
只不过字母不一定连续,但是保证了顺序是递增的
总结
Case 1: 已经处理完所有的位置,收集solution,减1把数字++
尝试把能的最后一位递增到原始given str中的下一位
Case 2:这个书自己超过了最大范围说明当前不合法必须回退到前一位
最大范围:这三位启示最大的就是原始given str中倒叙的后K位
对于查找谁是那个所谓的最高可以增大的位:倒叙遍历第一个不同的
最后一位找到了,他会变大成为谁呢?
Case 3:顺水推舟直到所有数字都递增
这一位以及这一位以后的所有字母都照搬given str
有一些浪费时间的String operation/use case
substring
indexOf
// Some code
class CombinationIterator {
char[] current;
String orignalStr;
boolean hasNext;
public CombinationIterator(String characters, int combinationLength) {
this.current = characters.substring(0,combinationLength).toCharArray();
this.originalStr = characters;
hasNext = true; // 注意CART
}
public String next(){
if (!hasNext) {
return "";
}
String result = new String(current);
int i = current.length - 1;
int j = originalStr.length() - 1;
while (i >= 0 && current[i] == originalStr.charAt(j)) {
i--;
j--;
}
if (i == -1) {
hasNext = false; // 没办法变化了
} else {
int index = priginalStr.indexOf(current[i]);
for (int k = i; k < current.length; k++) {
index++;
current[k] = originalStr.charAt(index);
}
}
return result;
}
public boolean hasNext(){
return this.hasNext;
}
}
Method 2 看use case的情况:需要连续的情况下不真的连续--》 bit mask(bit operation)
bitmask: 我用一个数字代表我的选择
bit:要么0代表不选,要么1代表选(一个位置上,几个进制代表几个状态)
abcd:选与不选这些字母的问题其实就是这四位的数字里哪些是1,哪些是0
易错点
最小的mask是谁?最小的size combination 0011(cd)
开始的mask怎么做出来的呢?
ab --》 1100
一开始最小的combination = (1 << totalLength) - (1 << (totalLength - combinationLength))
// Some code
class CombinationIterator {
private int combinationLength;
private String originalStr;
private int totalLength;
private int minBitmask;
private int bitmask; //current
private boolean foundNext;
public CombinationIterator(String characters, int combinationLength) {
this.orginalStr = character;
this.combinationLength = combinationLength;
this.totalLength = characters.length();
this.bitmask = (1 << totalLength) - (1 << (totalLength - combinationLength));
this.foundNext = true;
this.minBitmask = (1 << comibinationLength) - 1;
}
public String next(){
if (!hasNext()) {
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < totalLength; i++) {
if ((bitmask & (1 << totalLength - 1 - i) != 0)) {
sb.append(originalStr.charAt(i));
}
}
foundNext = false;
return sb.toString();
}
public boolean hasNext(){
if (foundNext) {
return true;
}
if (bitmask < minBitmask) {
return false;
}
bitmask --;
while (bitmask >= minBitmask && Integer.bitCount(bitmask) != combinationLength) {
bitmask--;
}
foundNext = bitmask >= minBitmask;
return foundNext;
}
}
API logic:
get next maskNumber:
能直接把currentmask 减1
1100(ab) - 1 = 1011(acd)
1011(acd) - 1= 1010(ac)
算法:逐次减1,直到得到hamming weight 和combinationLength一样的第一个mask
如何对应上Mask和String:bitGetter 把对应位是1的位填补位originalStr中对应character对于第i个index,是否要把它加到现在的current result里
(currentMask & (1 << n - 1 - i))!= 0
Side Problem 1: Number of 1Bits
Method 1: Java Library:
return Integer.bitCount(n);
Method 2: 自己实现
// Some code
int count = 0;
while (n != 0) {
count += (n & 1);
n >>> 1;
}
return count;
Method 3:技巧
// Some code
int count = 0;
while (n! = 0) {
n = n & (n - 1);
count++;
}
return count;
竞赛技巧: n& (n - 1)是什么意思
把n的二进制表示中最低的上的1改成0
example
n = 0b10100, n-1 = 0b10011
n & n-1 = 0b10000
example: 判断一个数字是不是2的幂次方
return n > 0 && (n & (n - 1) == 0)
Side Problem 2: Hamming Distance
本质上就是异或之后的数字中的hamming weight是多少
// Some code
public int hammingDistance(int x, int y) {
int number = x ^ y;
int count = 0;
while (number != 0) {
number = number & (number - 1);
count++;
}
return distance;
}
Last updated