代码随想录算法训练营第七天| 454 四数相加 II 383 赎金信 15 三数之和 18 四数之和
目录
383 赎金信
该题与242 有效的字母异位词思路相同
首先想到暴力写法,遍历magazine,将遍历到的元素记为ch,再遍历ransomNote,如果在ransomNode中找到了ch,就将两个字符串中的ch都删除,遍历完成后,如果ransomNode为空,则ransomeNode能由magazine里面的字符构成。时间复杂度O(n^2),空间复杂度为O(1)。
需要判断字符是否存在于字符串中,由此想到哈希解法,由题目提示
ransomNote和magazine由小写英文字母组成我们可知只需开辟一个大小为26的cnt数组进行存储,首先将遍历magazine,每遍历到一个字符,先将字符 - 'a'映射到0~25区间内,再进行一次++操作,接着遍历ransomNode,将字符-'a'之后进行一次--操作。最后遍历cnt数组,如果有小于0的值则可以判定ransomeNode不能由magazine里面的字符构成。
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if(ransomNote.length() > magazine.length())return false;
int cnt[] = new int[26];
for(char ch : magazine.toCharArray()){
cnt[ch - 'a'] ++;
}
for(char ch: ransomNote.toCharArray()){
cnt[ch - 'a']--;
}
for(int i = 0;i < 26;i++){
if(cnt[i] < 0)return false;
}
return true;
}
}
时间复杂度O(m + n),空间复杂度O(1)。
15 三数之和
采用双指针做法,先使nums按照非递减顺序排列,在循环中用i遍历nums取得,并对nums[i]进行去重操作,如果nums[i]大于0则一定不成立,退出循环并返回答案res。记i+1为l,nums.length-1为r,在第二层循环中求得三者之和sum后,如果三者之和大于0,则r--,小于,则l++,直至等于0后退出此循环并且进行对l与r的去重操作,最终加入res作为答案返回。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i = 0;i < nums.length;i++){
if(nums[i] > 0)return res;
if(i >= 1 && nums[i] == nums[i - 1])continue;
int l = i + 1,r = nums.length - 1;
while(r > l){
int sum = nums[l] + nums[r] + nums[i];
if(sum > 0)r--;
else if(sum < 0)l++;
else{
res.add(Arrays.asList(nums[i],nums[l],nums[r]));
while(r > l && nums[r] == nums[r - 1])r--;
while(r > l && nums[l] == nums[l + 1])l++;
r--;l++;
}
}
}
return res;
}
}
时间复杂度O(n^3),空间复杂度O(n)。
454 四数相加 II
由于本题不需要去重操作,可以使用哈希方法。在两层循环中遍历nums1与nums2 将和加入到map中。遍历nums3与nums4,在map中查找二者之和的负数的值,返回值res加上该值。
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4){
Map<Integer,Integer> mp = new HashMap<>();
int res = 0;
for(int i : nums1){
for(int j : nums2){
int sum = i + j;
if(mp.containsKey(sum)){
mp.put(sum,mp.get(sum) + 1);
}else{
mp.put(sum,1);
}
}
}
for(int i : nums3){
for(int j : nums4){
int sum = 0 - (i + j);
if(mp.containsKey(sum))res += mp.get(sum);
}
}
return res;
}
}
map.containsKey(key);取得map中key键的值
map.put(sum,cnt)设置key键的值为cnt
map.get(key)取得key键的值
时间复杂度O(n^2),空间复杂度O(n^2)。
18 四数之和
先使nums按非递减顺序排序。第一层循环中用i遍历nums,并进行去重操作,令j=i+1在第二层循环中进行遍历并去重,定义l等于j+1,r等于nums.length-1,在第三层循环计算sum等于四者相加,如果sum小于target则l++,大于则r--,当相等时对l与r进行去重,并加入到结果res中。
由于相比15 三数之和 (该题target为0,已经确定)本题target可以取负值,在进行剪枝操作时应该注意加上nums[i] > 0条件。样例 nums=[-4,-3,-2,-1],target = -10,这里nums[i] > target,但确实应该将nums加入到res中。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i = 0;i < nums.length;i++){
if(nums[i] > 0 && nums[i] > target)return res;
if(i > 0 && nums[i] == nums[i - 1])continue;
for(int j = i + 1;j < nums.length;j++){
if(j > i + 1 && nums[j] == nums[j - 1])continue;
int l = j + 1,r = nums.length - 1;
while(r > l){
int sum = nums[i] + nums[j] + nums[l] + nums[r];
if(sum > target)r--;
else if(sum < target)l++;
else{
res.add(Arrays.asList(nums[i],nums[j],nums[l],nums[r]));
while(r > l && nums[r] == nums[r - 1])r--;
while(r > l && nums[l] == nums[l + 1])l++;
r--;l++;
}
}
}
}
return res;
}
}
时间复杂度O(n^3),空间复杂度O(n)。
浙公网安备 33010602011771号