316. 去除重复字母
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
思路
1.使用hashmap或者数组,来记录每次字符出现的次数.
2.使用hashmap或者数组,来记录每个栈中存在字符。
3.先判断是否该字符是否存在,如果不存在,需要入栈。入栈前提需要对栈顶元素进行循环判断:栈不为空并且栈顶元素字典序大于该字符并且栈顶元素的出现次数大于0,满足则弹出。之后入栈,将存在设置为true。无论入栈与否都将出现次数-1。
完整代码
public String removeDuplicateLetters(String s) {
Stack<Character> s1 = new Stack<>();
Map<Character, Integer> map1 = new HashMap<>();//用来记录每个字符出现得次数
boolean[] exsist = new boolean[26];
for(int i = 0; i < s.length(); i++) {
if(map1.containsKey(s.charAt(i))) {
map1.put(s.charAt(i), map1.get(s.charAt(i)) + 1);
}else {
map1.put(s.charAt(i), 1);
}
}
for(int i = 0; i < s.length(); i++) {
char temp = s.charAt(i);
if(!exsist[temp - 'a']) {
while(!s1.isEmpty() && s1.peek() > temp && map1.get(s1.peek()) > 0) {
exsist[s1.pop() - 'a'] = false;
}
exsist[temp - 'a'] = true;
s1.add(temp);
}
map1.put(temp, map1.get(temp) - 1);
}
StringBuilder sb = new StringBuilder();
while (!s1.isEmpty()) {
sb.append(s1.pop());
}
return sb.reverse().toString();
}
338. 比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
思路1
这个题之前做过,先把每个数最右侧的1提取出来,异或去掉最右侧的1.循环即可。
语法
提取最右侧的1:N安危取反之后加1,再与原来的数相与
同时异或有两个性质:0 ^ N = N , N ^ N = 0.
N & ((~N) + 1);
完整代码
public int[] countBits(int num) {
int[] ans = new int[num + 1];
for (int i = 0; i <= num; i++) {
int curnum = i;
int cnt = 0;
while (curnum != 0) {
int rightOne = curnum & ((~curnum) + 1);
cnt++;
curnum ^= rightOne;
}
ans[i] = cnt;
}
return ans;
思路2
以上思路的时间复杂度为O(n*sizeof(integer))的解答,题目的进阶要求是要求算法的空间复杂度为O(n)。
也就是在一趟扫描的时间内完成
1.分为偶数和奇数来看
- 偶数a和偶数(a/2)的1的个数是一样的,因为只是左移了一位的关系
- 奇数b的末位一定是1,所以奇数只是比它小1的偶数多1。其1的个数也就是(b/2)的1的个数加1。
2.位运算
位运算通常是比四则运算快的,这里的除以2,我们可以用>>1(右移一位)来表示
- i & (i - 1):消掉二进制位中最右边的1.当i大于0的时候,i比特位数比i & (i - 1)多1
- i&1 :按位与运算,取 2进制整数 i 的最低位,如果最低位是1 则得1,反之得0
- a >> b & 1 代表检查 a 的第 b 位是否为 1,有两种可能性 0 或者 1
- a += 1 << b 代表将 a 的第 b 位设置为 1 (当第 b 位为 0 的时候适用,如不想写对第 b 位为 0 的前置判断,a += 1 << b 也可以改成 a |= 1 << b)
3.z综上,通过动态规划可以得到ans[i] = ans[i >> 1] + (i & 1)
完整代码
public int[] countBits(int num) {
int[] ans = new int[num + 1];
for(int i = 0; i < num + 1; i++) {
ans[i] = ans[i >> 1] + (i & 1);
}
return ans;
}