一、算法题
454.四数相加II
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer> map=new HashMap<>();
int count=0;
for(int i:nums1){
for(int j:nums2){
if(map.containsKey(i+j)){
//把值为i+j的数所对应的value+1,即出现次数+1
//不是新增一个数值相同的元素进map
map.put(i+j,map.get(i+j)+1);
}
else{
map.put(i+j,1);
}
}
}
for(int i:nums3){
for(int j:nums4){
if(map.containsKey(-i-j)){
count+=map.get(-i-j);
}
}
}
return count;
}
}
最后找到四个数相加为0的情况时,count不是等于count++的原因是:
- 这个数可能重复出现
- 比如a[1]+b[2]=5,a[2]+b[1]=5,此时map中{5:2}
- 那么在计算c+d时,如果c+d=-5,那么-c-d=5,此时可以找到两组使四数之和为0的数,如果使用count++那就只能找到一组,与题意不符
383. 赎金信
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if(ransomNote.length()>magazine.length()){
return false;
}
int []res=new int[26];
//顺序!
//先把magazine拿来遍历++,然后用ransomNote遍历--
//这样一旦出现小于0的数就说明ransomNote中有magazine没有的字符,也就无法拼成ransomNote
for(int i=0;i<magazine.length();i++){
res[magazine.charAt(i)-'a']++;
}
for(int i=0;i<ransomNote.length();i++){
res[ransomNote.charAt(i)-'a']--;
}
for(int i=0;i<26;i++){
if(res[i]<0){
return false;
}
}
return true;
}
}
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if(ransomNote.length()>magazine.length()){
return false;
}
int []res=new int[26];
//先把ransomNote遍历++再把magazine遍历--
//此时会出现三种情况:负数,0,大于0的数
//大于0的数就说明不满足题目要求
for(int i=0;i<ransomNote.length();i++){
res[ransomNote.charAt(i)-'a']++;
}
for(int i=0;i<magazine.length();i++){
res[magazine.charAt(i)-'a']--;
}
for(int i=0;i<26;i++){
if(res[i]>0){
return false;
}
}
return true;
}
}
两种不同增减顺序的情况
15. 三数之和
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){
//第一个数就大于0了说明怎么都不能使三元组和为0
return result;
}
if(i>0&&nums[i]==nums[i-1]){
//说明有重复元素,要去重
continue;
}
int left=i+1;
int right=nums.length-1;
//不能等于,因为等于的时候此时只有两个元素,构不成三元组
while(left<right){
if(nums[i]+nums[left]+nums[right]>0){
//移动right
right--;
}
else if(nums[i]+nums[left]+nums[right]<0){
left++;
}
else{
//此时nums[i]+nums[left]+nums[right]=0
//把这个三元组加入result
result.add(Arrays.asList(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--;
}
}
}
return result;
}
}
已解决问题:
- 当找到三元组之和等于0时,为什么最后要使left++且right--
- 因为找到三个数之后,如果单移动一个指针,即其他两个数不变,那么我们可以得到我们移动的那个指针一定要与刚找到的那个数相等
- 比如[-1,0,1],当我们移动left,即nums[ i ]= -1,nums[right]=1,只有nums[left]=0才能符合题意,但是如果nums[left]=0会被去重;反之移动单right也一样。所以要同时移动left和right
- Arrays.asList(nums[i], nums[left], nums[right])
Arrays.asList() 是将数组转化成List集合的方法
适用于对象型数据的数组(String、Integer…)
不建议使用于基本数据类型的数组(byte,short,int,long,float,double,boolean)
Arrays.sort(nums)
对指定数组按数字升序排序
未解决问题:
- left和right去重为什么放在后面问题
18. 四数之和
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0&&nums[i]>target){
//因为当nums[i]>0时,它与右边的数相加怎样都是>0的
//同时nums[i]>target,当四个数中最小的nums[i]都大于target了四数之和肯定会大于target
return result;
}
//去重
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 left=j+1;
int right=nums.length-1;
while(left<right){
int sum=nums[i]+nums[j]+nums[left]+nums[right];
if(sum>target){
right--;
}
else if(sum<target){
left++;
}
else{
result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
//去重
while(left<right&&nums[left]==nums[left+1]){
left++;
}
while(left<right&&nums[right]==nums[right-1]){
right--;
}
left++;
right--;
}
}
}
}
return result;
}
}