牛客网【面试必刷TOP101】~ 09 双指针

牛客网【面试必刷TOP101】~ 09 双指针

文章目录

    • 牛客网【面试必刷TOP101】~ 09 双指针
    • @[toc]
      • BM87 合并两个有序的数组(★)
      • BM88 判断是否为回文字符串(★)
      • BM89 合并区间(★★)
      • BM90 最小覆盖子串(★★★)
      • BM91 反转字符串(★)
      • BM92 最长无重复子数组(★★)
      • BM93 盛水最多的容器(★★)
      • BM94 接雨水问题(★★★)

BM87 合并两个有序的数组(★)

方法:双指针+逆序

归并排序中归并的思路

public class Solution {
    public void merge(int A[], int m, int B[], int n) {
        int k = m + n - 1;
        int i = m - 1, j = n - 1;
        while (i >= 0 || j >= 0) {
            if (i < 0) {
                A[k--] = B[j--];
            } else if (j < 0) {
                break;
            } else if (A[i] > B[j]) {
                A[k--] = A[i--];
            } else {
                A[k--] = B[j--];
            }
        }
    }
}

BM88 判断是否为回文字符串(★)

方法一:双指针

public class Solution {
    public boolean judge (String str) {
        int i = 0, j = str.length() - 1;
        while (i < j && str.charAt(i) == str.charAt(j)) {
            i++;
            j--;
        }
        return i >= j;
    }
}

BM89 合并区间(★★)

方法一:自定义排序

/*
 * public class Interval {
 *   int start;
 *   int end;
 *   public Interval(int start, int end) {
 *     this.start = start;
 *     this.end = end;
 *   }
 * }
 */

public class Solution {
    public ArrayList<Interval> merge (ArrayList<Interval> intervals) {
        ArrayList<Interval> res = new ArrayList<Interval>();
        if (intervals == null || intervals.size() == 0) return res;
        Collections.sort(intervals, (a, b) -> a.start - b.start);
        res.add(intervals.get(0));
 
        for (int i = 1; i < intervals.size(); i++) {
            Interval cur = intervals.get(i);
            Interval pre = res.get(res.size() - 1);
            if (pre.end >= cur.start) {
                pre.end = Math.max(pre.end, cur.end);
            } else {
                res.add(cur);
            }
        }

        return res;
    }
}

BM90 最小覆盖子串(★★★)

滑动窗口

  • 使用两个HashMap:一个保存标准字符串t的词频,另一个使用滑动窗口动态统计窗口内的词频,并检查区间是否符合规范。
public class Solution {
    Map<Character, Integer> std = new HashMap<>();
    Map<Character, Integer> cnt = new HashMap<>();

    public String minWindow (String S, String T) {
        for (char c : T.toCharArray()) {
            std.put(c, std.getOrDefault(c, 0) + 1);
        }

        int le = 0, ri = 0;
        int minLen = S.length() + 1, L = -1, R = -1;

        while (ri < S.length()) {
            // 只统计T中需要的字符
            if (std.containsKey(S.charAt(ri))) {
                cnt.put(S.charAt(ri), cnt.getOrDefault(S.charAt(ri), 0) + 1);
            }
            while (check() && le <= ri) {
                if (ri - le + 1 < minLen) {
                    minLen = ri - le + 1;
                    L = le;
                    R = ri;
                }
                if (cnt.containsKey(S.charAt(le))) {
                    cnt.put(S.charAt(le), cnt.getOrDefault(S.charAt(le), 0) - 1);
                }
                le++;
            }
            ri++;
        }

        return L == -1 ? "" : S.substring(L, R + 1);
    }

    private boolean check() {
        Iterator iter = std.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            Character key = (Character) entry.getKey();
            Integer val = (Integer) entry.getValue();
            if (cnt.getOrDefault(key, 0) < val) {
                return false;
            }
        }
        return true;
    }

}

BM91 反转字符串(★)

方法一:StringBuffer().reverse()(15ms)

public class Solution {
    public String solve (String str) {
        return new StringBuffer(str).reverse().toString();
    }
}

方法二:双指针(18ms)

public class Solution {
    public String solve (String str) {
        int n = str.length();
        char[] res = new char[n];
        for (int i = 0; i < n; i++) {
            res[i] = str.charAt(n - i - 1);
        }
        return new String(res);
    }
}

BM92 最长无重复子数组(★★)

方法一:双指针+HashSet

public class Solution {
    public int maxLength (int[] arr) {
        int res = 0;
        Set<Integer> set = new HashSet<>();

        for (int le = 0, ri = 0; ri < arr.length; ri++) {
            while (le < ri && set.contains(arr[ri])) {
                set.remove(arr[le]);
                le++;
            }
            res = Math.max(res, ri - le + 1);
            set.add(arr[ri]);
        }

        return res;
    }
}

BM93 盛水最多的容器(★★)

方法一:暴力法(超时(13/15)

public class Solution {
    public int maxArea (int[] height) {
        int res = 0;
        for (int i = 0; i < height.length; i++) {
            for (int j = i + 1; j < height.length; j++) {
                res = Math.max(res, (j - i) * Math.min(height[i], height[j]));
            }
        }
        return res;
    }
}

方法二:双指针(199ms)

public class Solution {
    public int maxArea (int[] height) {
        int res = 0;
        int le = 0, ri = height.length - 1;

        while (le <= ri) {
            if (height[le] < height[ri]) {
                res = Math.max(res, height[le] * (ri - le));
                le++;
            } else {
                res = Math.max(res, height[ri] * (ri - le));
                ri--;
            }
        }

        return res;
    }
}

BM94 接雨水问题(★★★)

方法一:暴力法、运行超时(8/11)

public class Solution {
    public long maxWater (int[] arr) {
        if (arr == null || arr.length < 3) return 0;
        int n = arr.length;
        long res = 0;

        for (int i = 1; i < n - 1; i++) {
            int leftMax = 0, rightMax = 0;
            for (int j = i - 1; j >= 0; j--) {
                leftMax  = Math.max(leftMax, arr[j]);
            }
            for (int j = i + 1; j < n; j++) {
                rightMax = Math.max(rightMax, arr[j]);
            }
            res += Math.max(0, Math.min(leftMax, rightMax) - arr[i]);
        }

        return res;
    }
}

方法二:空间换时间(301ms)

public class Solution {
    public long maxWater (int[] arr) {
        if (arr == null || arr.length < 3) return 0;
        int n = arr.length;

        int[] leftMax  = new int[n];
        int[] rightMax = new int[n];
        leftMax[0] = arr[0];
        for (int i = 1; i < n; i++) leftMax[i] = Math.max(leftMax[i - 1], arr[i]);
        rightMax[n - 1] = arr[n - 1];
        for (int i = n - 2; i >= 0; i--) rightMax[i] = Math.max(rightMax[i + 1], arr[i]);

        long res = 0;
        for (int i = 1; i < n - 1; i++) {
            res += (long)Math.max(0, Math.min(leftMax[i - 1], rightMax[i + 1]) - arr[i]);
        }

        return res;
    }
}

方法三:双指针(306ms)

public class Solution {
    public long maxWater (int[] arr) {
        if (arr == null || arr.length < 3) return 0;
        long res = 0;
        int le = 1, ri = arr.length - 2;
        int leftMax = arr[0], rightMax = arr[arr.length - 1];

        while (le <= ri) {
            if (leftMax < rightMax) {
                res += Math.max(0, leftMax - arr[le]);
                leftMax = Math.max(leftMax, arr[le++]);
            } else {
                res += Math.max(0, rightMax - arr[ri]);
                rightMax = Math.max(rightMax, arr[ri--]);
            }
        }

        return res;
    }
}

你可能感兴趣的:(双指针,Java,算法,面试,程序人生)