第454题.四数相加II
力扣题目链接
基本思路
- 要求的是有多少个组合满足,最坏循环遍历四个;最好分成两组,把一组a+b的和放到map的key,和出现的次数作为value,计算另一组,如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来
方法代码
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer, Integer> map1 = new HashMap<>();
int cont = 0;
for(int a : nums1){
for(int b : nums2){
map1.put(a+b, map1.getOrDefault(a+b, 0) + 1);
}
}
for(int c : nums3){
for(int d : nums4){
cont += map1.getOrDefault(0 - c - d, 0);
}
}
return cont;
}
}
- 时间复杂度:\(O(n^2)\)
- 空间复杂度:\(O(n^2)\),最坏情况下A和B的值各不相同,相加产生的数字个数为\(n^2\)
383. 赎金信
力扣题目链接
基本思路
- 和之前的字母异位词一样,使用一个数组记录存在的字母,通过自增自减判断是否符合条件
方法代码
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if (ransomNote.length() > magazine.length()) {
return false;
}
int[] arr = new int[26];
for (int c : magazine.toCharArray()) {
arr[c - 'a']++;
}
for (int c : ransomNote.toCharArray()) {
arr[c - 'a']--;
if (arr[c - 'a'] < 0) {
return false;
}
}
return true;
}
}
- 时间复杂度:\(O(n)\)
- 空间复杂度:\(O(1)\)
第15题. 三数之和
力扣题目链接
基本思路
- 先把数组排序,定义头尾的双指针,这样固定一个i之后就可以,根据sum的大小判断是需要更大的还是更小的值,从而根据排序数组的大小,更新指针指向
方法代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
List<List<Integer>> res = new ArrayList<>();
for(int i = 0 ; i < n - 2; i++){ //注意是n-2
int x = nums[i];
//跳过重复数字
if(i > 0 && x == nums[i - 1]) continue;
//如果最小的和大于0,直接结束
if(x + nums[i + 1] + nums[i + 2] > 0) break;
//如果最大j和k的和还小于0,则jk不变,跳到下一个循环,即更大的x
if(x + nums[n - 1] + nums[n - 2] < 0) continue;
//j,k是每次循环都要更新的
int j = i + 1;
int k = n - 1;
while(j < k){
int s = x + nums[j] + nums[k];
if(s > 0){
k--;
}else if(s < 0){
j++;
}else{
//找到一个三元组
res.add(List.of(x, nums[j], nums[k]));
//找到之后先更新两个指针
//看看指针变化之后是否重复,若有重复,则继续更新
j++;
while(j < k && nums[j] == nums[j - 1])
j++;
k--;
while(k > j && nums[k] == nums[k + 1])
k--;
}
}
}
return res;
}
}
- 时间复杂度:\(O(n^2)\)
- 空间复杂度:\(O(1)\)
注意点
- 注意如何去重,因为已经排序了,所以相等的值都会连在一起,所以通过判断当前数是否和前一个相等,来跳过重复值。
- 不能通过判断当前数是否和下一个数相等来跳过,因为
j = i + 1,这样会跳过j的可能取值
第18题. 四数之和
力扣题目链接
基本思路
- 和上三数之和一样,双指针,复杂度会提升n倍
方法代码
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
for(int i = 0; i < n - 3; i++){
if(i > 0 && nums[i] == nums[i - 1]) continue;
//第一个值是(long),后面的加法自动转换成(long)
//这里第一次最后一个nums[i + 3]就有可能超出int范围了,所以要先直接转型
if((long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
if((long)nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target) continue;
for(int j = i + 1; j < n - 2; j++){ //这里设置j为i+1,即可保证j在i后面
if(j > i + 1 && nums[j] == nums[j - 1]) continue;//这里设置j > i+1
if((long)nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
if((long)nums[i] + nums[j] + nums[n - 1] + nums[n - 2] < target) continue;
int k = j + 1;
int z = n - 1;
while(k < z){
long sum = (long)nums[i] + nums[j] + nums[k] + nums[z];
if(sum > target){
z--;
}else if(sum < target){
k++;
}else{
res.add(List.of(nums[i], nums[j], nums[k], nums[z]));
k++;
while(k < z && nums[k] == nums[k - 1])
k++;
z--;
while(z > k && nums[z] == nums[z + 1])
z--;
}
}
}
}
return res;
}
}
- 时间复杂度:\(O(n^3)\)
- 空间复杂度:\(O(1)\)
注意点
- 注意j的取值和循环条件,这种单个数组的都是根据i的值来确定初始值
- 注意观察题目是否会溢出,设置long来解决加法溢出的问题