目录
第 2 天 整数
1 只出现一次的数字
剑指 Offer II 004. 只出现一次的数字 https://leetcode-cn.com/problems/WGki4K/
1. 哈希表
class Solution {
public int singleNumber(int[] nums) {
Map<Integer, Integer> freq = new HashMap<Integer, Integer>();
for (int num : nums) {
freq.put(num, freq.getOrDefault(num, 0) + 1);
}
int ans = 0;
for (Map.Entry<Integer, Integer> entry : freq.entrySet()) {
int num = entry.getKey(), occ = entry.getValue();
if (occ == 1) {
ans = num;
break;
}
}
return ans;
}
}
2. 位运算
使用位运算将空间复杂度降低到O(1)。一般面试官会加上这个限制!
对于每一位的数字,除了目标数字外,每一个元素都出现 3 次,对应着第 i 个二进制位的 3 个 0 或 3 个 1,无论是哪一种情况,它们的和都是 3 的倍数(即和为 0 或 3)。借此目标数字的第 i 个二进制位就是数组中所有元素的第 i 个二进制位之和除以 3 的余数。
注意:
- 位运算 (x >> i) & 1 得到 x 的第 i 个二进制位
- 将它们相加再对 3 取余,得到的结果一定为 0 或 1,即为答案的第 i 个二进制位。
- 位运算 ans |=(1 << i ) 对结果每一个二进制位进行赋值。
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for (int i = 0; i < 32; ++i) {
int total = 0;
for (int num: nums) {
total += ((num >> i) & 1);
}
if (total % 3 != 0) {
ans |= (1 << i);
}
}
return ans;
}
}
3. 有限自动机
数电思想
2 单词长度的最大乘积
剑指 Offer II 005. 单词长度的最大乘积https://leetcode-cn.com/problems/aseY1I/
1. 暴力法
O(pq)
2. 哈希表
对每个字符串适用26个英文字母这个长度的哈希表存储出现在其中的字符。
在哈希表中查 O(1)。可以看做在应用哈希表后,判断两个字符串是否包含相同字符的时间复杂度为(1)。
class Solution {
public int maxProduct(String[] words) {
boolean[][] flags = new boolean[words.length][26];
for (int i = 0; i < words.length; i++) {
for(char c : words[i].toCharArray()){
flags[i][c-'a'] = true;
}
}
int result = 0;
for (int i = 0; i < words.length; i++) {
for (int j = 0; j < words.length; j++) {
int k = 0;
for (; k < 26; k++){
if(flags[i][k] && flags[j][k])
break;
}
if(26 == k){
int prod = words[i].length() * words[j].length();
result = Math.max(result, prod);
}
}
}
return result;
}
}
分析代码
共两步,第一步初始化哈希表 O(words的长度n * 平均字符串长度k),第二步 判断每对字符串是否包含相同字符 O(1) * O(n*n),总体上是O(nk+n*n)。
空间复杂度则是n*26 即O(n)
3. 整数的二进制数位记录出现的字符
记录是否出现使用的是布尔型数组,也可以利用二进制!
Java中int型整数二进制有32位,so~
class Solution {
public int maxProduct(String[] words) {
int[] flags = new int[words.length];
for (int i = 0; i < words.length; i++) {
for (char c : words[i].toCharArray()) {
flags[i] |= 1 << (c - 'a');
}
}
int result = 0;
for (int i = 0; i < words.length; i++) {
for (int j = 0; j < words.length; j++) {
if ((flags[i] & flags[j]) == 0) {
int prod = words[i].length() * words[j].length();
result = Math.max(result, prod);
}
}
}
return result;
}
}
3 排序数组中两个数字之和
剑指 Offer II 006. 排序数组中两个数字之和https://leetcode-cn.com/problems/kLl5u1/
1. 遍历
2.双指针法
package zxtp.Day01;
import java.util.Arrays;
/**
* @author ahan
* @create_time 2022-01-23-6:10 下午
*/
public class _006 {
public static void main(String[] args) {
System.out.println(Arrays.toString(new _006().twoSum(new int[]{1,2,4,6,10}, 8)));
}
public int[] twoSum(int[] numbers, int target) {
int[] res = new int[2];
for (int i = 0, j = numbers.length - 1; i <= j; ) {
int sum = numbers[i] + numbers[j];
System.out.println(sum);
if(sum == target){
res[0] = i;
res[1] = j;
break;
}
else if(sum > target)
j--;
else
i++;
}
return res;
}
}