454 四数相加Ⅱ
思路:把两个分成两组,组内的两组合并求和与另一组相比较,如果存在元素则求两个key的笛卡尔积
数据结构:由于数字相加后很大可能为相同的 Set里不存储重复元素 需要用Map计数,因此选用HashMap
代码:
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
// 思路:把两个分成两组,组内的两组合并求和与另一组相比较,如果存在元素则求两个key的笛卡尔积
// 数据结构:为什么使用Map而不用Set - 由于数字相加后很大可能为相同的 Set里不存储重复元素 需要用Map计数
HashMap<Integer, Integer> hm1 = new HashMap<>();
for (int i : nums1) {
for (int i1 : nums2) {
int sum = i + i1;
if (hm1.containsKey(sum)) {
Integer integer = hm1.get(sum);
hm1.put(sum, ++integer);
}
else {
hm1.put(sum, 1);
}
}
}
HashMap<Integer, Integer> hm2 = new HashMap<>();
for (int i : nums3) {
for (int i1 : nums4) {
int sum = i + i1;
if (hm2.containsKey(sum)) {
Integer integer = hm2.get(sum);
hm2.put(sum, ++integer);
}
else {
hm2.put(sum, 1);
}
}
}
int count = 0;
for (Integer key : hm1.keySet()) {
if (hm2.containsKey(-key) && hm2.get(-key) != 0) {
// 求笛卡尔积
count += hm1.get(key) * hm2.get(-key);
}
}
return count;
}
383 赎金信
数据结构:
- 题目中:是否由字符构成 - Hash
- 涉及到重复元素:HashMap
思路:将magazine里字母放进HashMap,由ransomNote去减,都是零则true,否则false
public boolean canConstruct(String ransomNote, String magazine) {
// 数据结构:
// 题目中:是否由字符构成 - Hash
// 涉及到重复元素:HashMap
// 思路:将magazine里字母放进HashMap,由ransomNote去减,都是零则true,否则false
// 放进HashMap
HashMap<Character, Integer> hm = new HashMap<>();
for (int i = 0; i < magazine.length(); i++) {
Character key = magazine.charAt(i);
if (hm.containsKey(key)){
Integer integer = hm.get(key);
hm.put(key, ++integer);
}
else {
hm.put(key, 1);
}
}
// 删 - 有就删 - 连对应的字符都没有就false
for (int i = 0; i < ransomNote.length(); i++) {
Character key = ransomNote.charAt(i);
if (hm.containsKey(key)){
Integer integer = hm.get(key);
// 没有返回false
if (integer - 1 < 0){
return false;
}
// 有就删一个
hm.put(key, --integer);
}
// 连记录都没有返回false
else {
return false;
}
}
return true;
}
15 三数之和
🔴变化:把所有数都放一个数组里,且要求不重复
- 都在一个数组 - 双指针
- 不重复 - 剪枝与去重
🔴难点:
- 想到三指针法 - 先排序
- 去重:1.左右指针去重 2.i元素去重
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
// 排序
int[] arr = Arrays.stream(nums).sorted().toArray();
for (int i = 0; i < arr.length; i++) {
// 剪枝 - 都是正数
if (arr[i] > 0) return list;
// 去重 - i元素
if (i >0 && arr[i] == arr[i - 1]){
continue;
}
// 定义指针
int left = 1 + i;
int right = arr.length - 1;
while (right > left){
int sum = arr[i] + arr[left] + arr[right];
if (sum == 0){
// 获得元素
list.add(Arrays.asList(arr[i],arr[left],arr[right]));
// 左右指针去重
while (right > left && arr[right] == arr[right - 1]) right--;
while (right > left && arr[left] == arr[left + 1]) left++;
// 更新位置
left++;
right--;
} else if (sum > 0) {
// 数变小
right--;
}else left++;
}
}
return list;
}
18 四数之和
🔴变化:把所有数都放一个数组里,且要求不重复,数字增加到了四个
- 都在一个数组 - 双指针
- 不重复 - 剪枝与去重
- 数字增加到四个 - 再加多一个指针 嵌套一层循环
🔴思路:在三数之和的基础上嵌套一层循环 🔴难点:剪枝与去重
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> list = new ArrayList<>();
// 1. 排序数组
Arrays.sort(nums);
// 2.结合新元素k的三数之和 - 三数之和再套壳一层循环
for (int k = 0; k < nums.length; k++) {
// 判断 - 减枝
if (nums[k] > target && nums[k] > 0)
break;
// 判断 - 去重
if (k > 0 && nums[k - 1] == nums[k])
continue;
for (int i = k + 1; i < nums.length; i++) {
// 剪枝
if (nums[k] + nums[i] > target && nums[k] + nums[i] > 0)
break;
// 去重 - i移动后与前面元素相同
if (i > k + 1 && nums[i] == nums[i - 1])
continue;
// left 与 right 往内缩
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) {
list.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));
// 去重 - left 与 right 元素相同
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
left++;
right--;
} else if (sum > target) {
right--;
}else left++;
}
}
}
return list;
}