春招冲刺百题计划|滑动窗口

Java基础复习

  1. Java数组的声明与初始化
  2. Java ArrayList
  3. Java HashMap
  4. Java String 类
  5. Java LinkedList
  6. Java Deque继承LinkedList
  7. Java Set
  8. Java 队列
  9. 优先队列!!!
  10. Java数组划分
  11. Java数组转ArrayList
  12. String 转数字
  13. String

第一题:187. 重复的DNA序列

在这里插入图片描述
还是比较简单的:

class Solution {
    public List<String> findRepeatedDnaSequences(String s) {
        List<String> results = new ArrayList<>();
        Map<String, Integer> map  = new HashMap<>();
        for(int i=0; i+10<=s.length(); i++){
            String subs = s.substring(i, i+10);
            map.put(subs, map.getOrDefault(subs, 0)+1);
        }
        for(String tmp: map.keySet()){
            if(map.get(tmp)>=2){
                results.add(tmp);
            }
        }
        return results;


    }
}

第二道:219. 存在重复元素 II

在这里插入图片描述
最简单就是一个二重循环,但是嗯,还是想要自己想一想滑动窗口怎么写出来。

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        //固定窗口大小
        for(int m=1; m<=k; m++){
            for(int i=0; i+m<nums.length; i++){
                if(nums[i]==nums[i+m]){
                    return true;
                } 
            }
        }
        //暴力解法
        // for(int i=0; i<nums.length; i++){
        //     for(int j=i+1; j<nums.length&&j<=i+k; j++){
        //         if(nums[i]==nums[j]){
        //             return true;
        //         }
        //     }
        // }
        return false;

    }
}

但我觉得两者在正常情况下时间复杂度一样啊。
真无语,看题解,用得到哈希表。
真正有用的还是set,map,优先队列这种包装好的数据结构啊!!!

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        int n = nums.length;
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < n; i++) {
            if (i > k) set.remove(nums[i - k - 1]);
            if (set.contains(nums[i])) return true;
            set.add(nums[i]);
        }
        return false;
    }
}

第三题:658. 找到 K 个最接近的元素

在这里插入图片描述
个人觉得优先队列就是万能的神!!

class Solution {
    static Comparator<List<Integer>> cmp = new Comparator<List<Integer>>() {
      public int compare(List<Integer> e1, List<Integer> e2) {
        if(e1.get(0) - e2.get(0)==0){
            return e1.get(2) - e2.get(2);
        }
        return e1.get(0) - e2.get(0);
      }
    };
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        //优先队列
        List<Integer> results = new ArrayList<>();
        Queue<List<Integer>> q = new PriorityQueue<>(cmp);
        for(int i=0; i<arr.length; i++){
            List<Integer> tmp = new ArrayList<>();
            tmp.add(Math.abs(arr[i]-x));
            tmp.add(arr[i]);
            tmp.add(i);
            q.offer(tmp);
        }
        for(int i=0; i<k; i++){
            results.add(q.poll().get(1));
        }
        Collections.sort(results);
        return results;
    }
}

官方直接用原数组排序代码也很优雅。还有一种双指针+二分查找的方法!(分为两拨,一波<x,一波>x,然后在两拨找答案)。比我写得优雅太多了。

class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        List<Integer> list = new ArrayList<Integer>();
        for (int num : arr) {
            list.add(num);
        }
        Collections.sort(list, (a, b) -> {
            if (Math.abs(a - x) != Math.abs(b - x)) {
                return Math.abs(a - x) - Math.abs(b - x);
            } else {
                return a - b;
            }
        });//lambda表达式
        List<Integer> ans = list.subList(0, k);
        Collections.sort(ans);
        return ans;
    }
}
class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int right = binarySearch(arr, x);
        int left = right - 1;
        while (k-- > 0) {
            if (left < 0) {
                right++;
            } else if (right >= arr.length) {
                left--;
            } else if (x - arr[left] <= arr[right] - x) {
                left--;
            } else {
                right++;
            }
        }
        List<Integer> ans = new ArrayList<Integer>();
        for (int i = left + 1; i < right; i++) {
            ans.add(arr[i]);
        }
        return ans;
    }

    public int binarySearch(int[] arr, int x) {
        int low = 0, high = arr.length - 1;
        while (low < high) {
            int mid = low + (high - low) / 2;
            if (arr[mid] >= x) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }
        return low;
    }
}

第四题:718. 最长重复子数组

在这里插入图片描述
及其暴力的方法,必然超时。

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        //原本的思路是短的数组直接怼上去一个一个对。现在发现起始位置不一定是0啊。
        int[] mi = nums1.length<=nums2.length? nums1:nums2;
        int[] ma = nums1.length<=nums2.length? nums2:nums1;
        System.out.println(Arrays.toString(ma));
         System.out.println(Arrays.toString(mi));
        int res=0, tmp=0;
        for(int k=mi.length; k>=0; k--){
            for(int s=0; s+k<=mi.length; s++){  
                for(int i=0; i+k<=ma.length; i++){
                    tmp=0;
                    for(int j=s; j<s+k; j++){
                        System.out.print(j);
                        System.out.print(" ");
                        System.out.print(i+j-s);
                        System.out.print(" ");
                        if(mi[j]!=ma[i+j-s]){
                            res = Math.max(tmp, res);
                            tmp = 0;
                        }else{
                            tmp++;
                        }
                        System.out.println(tmp);
                    }
                    res = Math.max(tmp, res);
                    if(res>=k){
                        return res;
                    }
                }
                
            }
        }
        return res;
        }
         
}

看了题解才明白,自己原来的贴贴法,再改进一下就有啦

具体参考题解:https://leetcode.cn/problems/maximum-length-of-repeated-subarray/solutions/28583/wu-li-jie-fa-by-stg-2
就是好厉害呀!

class Solution {
    public int findLength(int[] A, int[] B) {
        return A.length <= B.length ? findMax(A, B) : findMax(B, A);
    }

    private int findMax(int[] A, int[] B) {
        int m = A.length, n = B.length;
        int max = 0;

        /*
        A:           |*|*|*|*|
        B: |*|*|*|*|*|*|
                 ↓
        A:       |*|*|*|*|
        B: |*|*|*|*|*|*|
         */
        for (int len = 1; len < m; len++) {
            max = Math.max(max, find(A, B, 0, n - len, len));
        }

        /*
        A:     |*|*|*|*|
        B: |*|*|*|*|*|*|
                 ↓
        A: |*|*|*|*|
        B: |*|*|*|*|*|*|
         */
        for (int j = n - m; j >= 0; j--) {
            max = Math.max(max, find(A, B, 0, j, m));
        }

        /*
        A: |*|*|*|*|
        B:   |*|*|*|*|*|*|
                 ↓
        A: |*|*|*|*|
        B:       |*|*|*|*|*|*|
         */
        for (int len = m - 1; len > 0; len--) {
            max = Math.max(max, find(A, B, m - len, 0, len));
        }

        return max;
    }

    private int find(int[] A, int[] B, int i, int j, int len) {
        int max = 0, count = 0;
        for (int k = 0; k < len; k++) {
            if (A[i + k] == B[j + k]) {
                count++;
            } else {
                max = Math.max(max, count);
                count = 0;
            }
        }

        return Math.max(max, count);
    }
}

还有几题困难题,等全部结束再来。以上个人感觉都是非常有趣的题目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值