哈希表篇
哈希表
有效的字母异位词
/**
* 242. 有效的字母异位词 字典解法
* 时间复杂度O(m+n) 空间复杂度O(1)
*/
class Solution {
public boolean isAnagram(String s, String t) {
int[] record = new int[26];
for (int i = 0; i < s.length(); i++) {
record[s.charAt(i) - 'a']++; // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
}
for (int i = 0; i < t.length(); i++) {
record[t.charAt(i) - 'a']--;
}
for (int count: record) {
if (count != 0) { // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
return false;
}
}
return true; // record数组所有元素都为零0,说明字符串s和t是字母异位词
}
}
注解:
这道题我在一开始做的时候没想到这种方法,当时想的可能是把字符按照从a到z排好,然后看最后两个字符串一样不一样。
两个数组的交集
import java.util.HashSet;
import java.util.Set;
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
return new int[0];
}
Set<Integer> set1 = new HashSet<>();
Set<Integer> resSet = new HashSet<>();
//遍历数组1
for (int i : nums1) {
set1.add(i);
}
//遍历数组2的过程中判断哈希表中是否存在该元素
for (int i : nums2) {
if (set1.contains(i)) {
resSet.add(i);
}
}
//方法1:将结果集合转为数组
###mapToInt 是流的一个中间操作,它的作用是将流中的每个元素按照指定的函数进行映射转换,这里的函数是一个 Lambda 表达式 x -> x。
对于 mapToInt 流,toArray() 方法最终会生成一个整数类型的数组,其元素就是原来集合 resSet 中经过转换后的整数元素。
return resSet.stream().mapToInt(x -> x).toArray();
//方法2:另外申请一个数组存放setRes中的元素,最后返回数组
int[] arr = new int[resSet.size()];
int j = 0;
for(int i : resSet){
arr[j++] = i;
}
return arr;
}
}
我用的方法
import java.util.ArrayList;
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] cur1 = new int[1001];
int[] cur2 = new int[1001];
List<Integer> comp = new ArrayList<>();
for (int i : nums1) {
cur1[i] = 1;
}
for (int i : nums2) {
cur2[i] = 1;
}
for (int i=0; i<=1000; i++) {
if (cur1[i]==1 && cur2[i]==1) {
comp.add(i);
}
}
#############下面这个地方不是我想的,我自己这个地方没有解决#########
int index = 0;
int res[] = new int[comp.size()];
for (int i : comp) {
res[index++] = i;
}
return res;
}
}
快乐数
看的答案解析
class Solution {
public boolean isHappy(int n) {
Set<Integer> record = new HashSet<>();
while (n != 1 && !record.contains(n)) {
record.add(n);
n = getNextNumber(n);
}
return n == 1;
}
private int getNextNumber(int n) {
int res = 0;
while (n > 0) {
int temp = n % 10;
res += temp * temp;
n = n / 10;
}
return res;
}
}
两数之和
哈希表1,这个里面通过一遍循环,完成查找工作。
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] res = new int[2];
if (nums == null || len == 0) {
return res;
}
Map<Integer, Integer> map = new HashMap<>();
for (int i=0; i<len; i++) {
int temp = target - nums[i];
if (map.containsKey(temp)) {
res[1] = i;
res[0] = map.get(temp);
break;
}
map.put(nums[i], i);
}
return res;
}
}
使用哈希表方法2
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> indexMap = new HashMap<>();
for (int i=0; i<nums.length; i++) {
int balance = target - nums[i];
if (indexMap.containsKey(balance)) {
return new int []{i, indexMap.get(balance)};
} else {
indexMap.put(nums[i], i);
}
}
}
}
我自己写的
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] cur = new int[2];
for (int i=0; i<len-1; i++) {
for (int j=i+1; j<len; j++) {
if (nums[i]+nums[j] == target) {
cur[0] = i;
cur[1] = j;
}
}
}
return cur;
}
}
陌生-四数相加||
官方代码
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res = 0;
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//统计两个数组中的元素之和,同时统计出现的次数,放入map
for (int i : nums1) {
for (int j : nums2) {
int sum = i + j;
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
}
//统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数
for (int i : nums3) {
for (int j : nums4) {
res += map.getOrDefault(0-i-j, 0);
}
}
return res;
}
}
了解-赎金信
官方代码
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if (ransomNote.length() > magazine.length()) return false;
int[] record = new int[26];
// toCharArray 主要作用是将一个String对象转换为一个字符数组
for (char c : magazine.toCharArray()) {
record[c - 'a'] += 1;
}
for (char c : ransomNote.toCharArray()) {
record[c - 'a'] -= 1;
}
// 如果数组中存在负数,说明ransomNote字符串中存在magazine中没有的字符
for (int i : record) {
if (i < 0) {
return false;
}
}
return true;
}
}
陌生-多看-三数之和
双指针法
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for (int i=0; i<nums.length; i++) {
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if (nums[i] > 0) {
return result;
}
if (i>0 && nums[i]==nums[i-1]) {
continue;
}
int left = i + 1;
int right =nums.length - 1;
while (right > left) {
int sum = nums[i] + nums[left] + nums[right];
if (sum > 0) {
right--;
} else if (sum < 0) {
left++;
} else {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
right--;
left++;
}
}
}
return result;
}
}
这个题解题思想要了解清楚。
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
这个地方需要理清楚。
四数之和
随想录给的代码:
public class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums); // 排序数组
List<List<Integer>> result = new ArrayList<>(); // 结果集
for (int k = 0; k < nums.length; k++) {
// 剪枝处理
if (nums[k] > target && nums[k] >= 0) {
break;
}
// 对nums[k]去重
if (k > 0 && nums[k] == nums[k - 1]) {
continue;
}
for (int i = k + 1; i < nums.length; i++) {
// 第二级剪枝
if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
break;
}
// 对nums[i]去重
if (i > k + 1 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (right > left) {
long sum = (long) nums[k] + nums[i] + nums[left] + nums[right];
if (sum > target) {
right--;
} else if (sum < target) {
left++;
} else {
result.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));
// 对nums[left]和nums[right]去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
right--;
left++;
}
}
}
}
return result;
}
相当于在三数之和的基础上再套一层代码。