打卡代码随想录Day3

有关求和:

1.三数之和(力扣15)

双指针的应用,注意在什么条件下指针如何移动,还有就是要求返回的三元组不重复。

public List<List<Integer>> threeSum(int[] nums) {
    Set<List<Integer>> r = new HashSet<>();
    List<List<Integer>> res = new ArrayList<>();
    if(nums.length < 3)
        return res;
    Arrays.sort(nums);
    if(nums[0] > 0 || nums[nums.length-1] < 0)
        return res;
    if(nums[0] == 0 && nums[1] == 0 && nums[2] == 0){
        res.add(Arrays.asList(0, 0, 0));
        return res;
    }
    int left;
    int right;
    for (int i = 0; i < nums.length-2; i++) {
        if(nums[i]>0)
            break;
        left = i+1;
        right = nums.length-1;
        while (left<right)
        {
            if(nums[i]+nums[left]+nums[right] == 0)
                r.add(Arrays.asList(nums[i],nums[left],nums[right]));
            if(nums[i]+nums[left]+nums[right] < 0)
                left++;
            else
                right--;
        }
    }
    res.addAll(r);
    return res;
}

2.四数之和(力扣18)

整体思路是在三数之和的基础上再套一个for循环,但在第一题的基础上还进行了更好的去重。

public List<List<Integer>> fourSum(int[] nums, int target) {
    List<List<Integer>> res = new ArrayList<>();
    if(nums.length < 4)
        return res;
    Arrays.sort(nums);
    int left;
    int right;
    for (int i = 0; i < nums.length-3; i++) {
        if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
        for (int j = i+1; j < nums.length-2; j++) {
            if(j>i+1 && nums[j] == nums[j-1]) continue; // 去重
            left = j + 1;
            right = nums.length-1;
            while (left<right){
                int sum = nums[i]+nums[j]+nums[left]+nums[right];
                if(sum == target){
                    res.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--;
                }
                if(sum < target)
                    left++;
                if(sum > target)
                    right--;
            }
        }
    }
    return res;
}

有关哈希表的练习,该结构使用空间换取时间,以便在查找某元素是否存在时快速判断出结果:

1.有效的字母异位词(力扣242):用HashMap的方式需要判断两个字符串中每个元素出现的次数是否一样;用转为字符数组的方式可以通过排序后遍历来看,若两个字符数组排序后相同则一定是有效的字母异位词。

public boolean isAnagram(String s, String t) {
        if(s.length() != t.length())
            return false;
        Map<Character,Integer> hm = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            hm.put(s.charAt(i),hm.getOrDefault(s.charAt(i),0)+1);
        }
        for (int i = 0; i < t.length(); i++) {
            hm.put(t.charAt(i),hm.getOrDefault(t.charAt(i),0)-1);
            if(hm.get(t.charAt(i))<0)
                return false;
        }
        return  true;
//        if(s.length()!=t.length())
//            return false;
//        char[] chars = s.toCharArray();
//        char[] chart = t.toCharArray();
//        Arrays.sort(chars);
//        Arrays.sort(chart);
//        int i = 0;
//        return Arrays.equals(chars,chart);
    }

2.赎金信(力扣383)

问题通过哈希表解决,需要的字符在表中值加一,能满足的字符在表中值减一,若最终表中没有值大于零的字符则满足。注意:.getOrDefault(Object key,Object defaultValue)方法,当key在表中时返回对应的value,否则返回defaultValue。

public boolean canConstruct(String ransomNote, String magazine) {
    if(ransomNote.length()>magazine.length())
        return false;
    HashMap<Character,Integer> hm = new HashMap<>();
    for (int i = 0; i < ransomNote.length(); i++) {
        hm.put(ransomNote.charAt(i),hm.getOrDefault(ransomNote.charAt(i),0)+1);
    }
    for (int i = 0; i < magazine.length(); i++) {
        hm.put(magazine.charAt(i),hm.getOrDefault(magazine.charAt(i),0)-1);
    }
    for (Integer value : hm.values()) {
        if (value>0)
            return false;
    }
    return true;
}

*3.字母异位词分组(力扣49)

由于字母异位词在对字母排序后是相同的字符串,以此作为哈希表的key,将具有相同特性的词构成一个列表作为哈希表的value。最后哈希表中values即为各个分组。注意哈希表的key可以表示同一类型(字母排序后相等的字符串)的标签,具有唯一性,value保存该类型的所有词组。该题值得复习。

public List<List<String>> groupAnagrams(String[] strs) {
    List<List<String>> res = new ArrayList<>();
    Map<String,List<String>> hm = new HashMap<>();
    for (int i = 0; i < strs.length; i++) {
        char[] arr = strs[i].toCharArray();
        Arrays.sort(arr);
        String key = new String(arr);
        List<String> list = hm.getOrDefault(key,new ArrayList<>());
        list.add(strs[i]);
        hm.put(key,list);
    }
    res.addAll(hm.values());
    return res;
}

4.找到字符串中所有字母异位词(力扣438)

由上题给的思路将短的那个字符串中字母排序后放入map,当作key,然后使用与短的字符串等长的滑动窗口在长的字符串中找到与map的key互为字母异位词的单词,将下标保存进map的value中。其中value存放的是符合条件的位置下标构成的数组。

public List<Integer> findAnagrams(String s, String p) {
    if(s.length()<p.length())
        return new ArrayList<Integer>();
    HashMap<String,ArrayList<Integer>> hm = new HashMap<>();
    char[] charp = p.toCharArray();
    Arrays.sort(charp);
    hm.put(new String(charp),new ArrayList<>());
    char[] chars = s.toCharArray();
    for (int i = 0; i < chars.length-(p.length()-1); i++) {
        String t= new String(chars,i,p.length());
        char[] chart = t.toCharArray();
        Arrays.sort(chart);
        String str = new String(chart);
        if(hm.get(str) != null){
            ArrayList list = hm.get(str);
            list.add(i);
            hm.put(str, list);
        }
    }
    return hm.get(new String(charp));
}

5.两个数组的交集(力扣349)

注意保证返回的数组中的值具有唯一性。

public int[] intersection(int[] nums1, int[] nums2) {
        //hs用来存放第一个数组中出现过的元素
        HashSet<Integer> hs = new HashSet<>();
        //放入hashSet保证返回的数组中没有重复值。
        HashSet<Integer> r = new HashSet<>();
        for (int i = 0; i < nums1.length; i++) {
            hs.add(nums1[i]);
        }
        for (int i = 0; i < nums2.length; i++) {
            if (hs.contains(nums2[i]))
                r.add(nums2[i]);
        }
        int[] res = new int[r.size()];
        Iterator iterator = r.iterator();
        int i = 0;
        while (iterator.hasNext()){
            res[i++] = (Integer)iterator.next();
        }
        return res;
//        //双指针法,将排序后的两数组同时设置指针,若指向数字相同则放入新的数组,否则小的向后移,直至末尾,注意新数组插入的唯一性
//        Arrays.sort(nums1);
//        Arrays.sort(nums2);
//        int length1 = nums1.length;
//        int length2 = nums2.length;
//        int index1 = 0;
//        int index2 = 0;
//        int index = 0;
//        int[] intersection = new int[length1 + length2];
//        while (index1 < length1 && index2 < length2){
//            if(nums1[index1] == nums2[index2]){
//                if( index==0 || nums1[index1]!=intersection[index-1])
//                    intersection[index++] = nums1[index1];
//                index1++;
//                index2++;
//            }
//            else
//                if(nums1[index1] < nums2[index2])
//                    index1++;
//                else
//                    index2++;
//        }
//        return Arrays.copyOfRange(intersection,0,index);
    }

6.两个数组的交集2(力扣350)

不需要考虑返回数组中元素的唯一性,直接双指针。

public int[] intersect(int[] nums1, int[] nums2) {
    Arrays.sort(nums1);
    Arrays.sort(nums2);
    int[] intersect = new int[nums1.length + nums2.length];
    int index1 = 0;
    int index2 = 0;
    int index = 0;
    while (index1 < nums1.length && index2 < nums2.length){
        if(nums1[index1] == nums2[index2]){
            intersect[index++] = nums1[index1];
            index1++;
            index2++;
        }
        else
            if(nums1[index1] < nums2[index2])
                index1++;
            else
                index2++;
    }
    return Arrays.copyOfRange(intersect,0,index);
}

7.快乐数(力扣202)

由于不是快乐数就会回到原来那个数,用Set不可重复的特性做,若add失败了则必然是回到了原来的那个数。

public boolean isHappy(int n) {
    //若不是快乐数则必然回到那个数,则hs.add(n)返回false
    if(n == 1)
        return true;
    HashSet<Integer> hs = new HashSet<>();
    while (n!=1 && hs.add(n)){
        int sum = 0;
        while (n!=0){
            sum += (n%10)*(n%10);
            n = n/10;
        }
        n = sum;
    }
    return n==1;
}

8.两数之和(力扣1)

用HashMap存放target和数组中每一个数的差,key是差,value是数组中那个数的下标,再次遍历数组时若遍历到一个数是map的key且其下标和key对应的value不同(避免数组中同一个元素用了两次)则找到这两个数。即map中的key存放需要匹配的数,value存放要求返回的下标。

public int[] twoSum(int[] nums, int target) {
    HashMap<Integer,Integer> hm = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        hm.put(target-nums[i],i);
    }
    for (int i = 0; i < nums.length; i++) {
        if(hm.containsKey(nums[i])&&(i!=hm.get(nums[i])))
            return new int[]{i,hm.get(nums[i])};
    }
    return new int[]{};
}

*9.四数之和2(454)

继续沿用HashMap中key放所需要匹配的数的方法。

public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
    Map<Integer,Integer> hm = new HashMap<>();
    int res = 0;
    for (int i = 0; i < nums1.length; i++) {
        for (int j = 0; j < nums2.length; j++) {
            hm.put(-nums1[i]-nums2[j],hm.getOrDefault(-nums1[i]-nums2[j],0)+1);
        }
    }
    for (int i = 0; i < nums3.length; i++) {
        for (int j = 0; j < nums4.length; j++) {
            if(hm.containsKey(nums3[i]+nums4[j]))
                res+=hm.get(nums3[i]+nums4[j]);
        }
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值