前缀和(本质:空间换时间)

1. 数组种的双指针

借助一个变量做到了降维的优化

1.1 左右指针

class Solution {
    public int maxArea(int[] height) {
    	int left = 0;
    	int right = height.length - 1;
    	int max = 0;
    	while (left <= right){
    		int area = (right - left) * Math.min(height[left], height[right]);
    		max = Math.max(max, area);
    		if (height[left] <= height[right]){	//	说明 height[left] 与右边任意线段都无法组成一个比 ans 更大的面积【因为高已确定,就是height[left]】
    			left++;
			}else {
    			right--;
			}
		}
    	return max;
	}
}

1.2 快慢指针

1.3 2个数组,用 2 个指针分别遍历

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
    	int start1 = 0;
    	int start2 = 0;
    	int index = 0;
		int[] arr = Arrays.copyOf(nums1, m);
		while (start1 < m && start2 < n){
			int A = arr[start1];
			int B = nums2[start2];
			if (A <= B){
				start1++;
			}else {
				start2++;
			}
			nums1[index++] = Math.min(A, B);
		}
    	if (start1 == m){
			for (int i = start2; i < nums2.length; i++) {
				nums1[index++] = nums2[i];
			}
		}
    	if (start2 == n){
			for (int i = start1; i < arr.length; i++) {
				nums1[index++] = arr[i];
			}
		}
	}
}

2. 前缀和

1204. 统计【优美子数组】:k > 1 (默认

cclass Solution {
    public int numberOfSubarrays(int[] nums, int k) {
    	//	通过 % 2 将找 k 个奇数的子数组 ===> 找和为k 的子数组 ==> s[i] - s[j] = k ===> 2数之和
		//	[1 1 2 1 1]
		//	1 1 0 1 1
		//	s[i]:nums[0] - nums[i] 和 ===> 非递减数列
		//	即:0 1 2 2 3 4 【注意前面要补个 0】
		//	两数之和
		int[] s = new int[nums.length + 1];
		for (int i = 1; i < s.length; i++) {
			s[i] = s[i - 1] + nums[i - 1] % 2;
		}
		Map<Integer, Integer> map = new HashMap<>();
		int count = 0;
		for (int i = 1; i < s.length; i++) {
			if (s[i] == k){
				count++;
			}
			count += map.getOrDefault(s[i] - k, 0);
			map.put(s[i], map.getOrDefault(s[i], 0) + 1);	//	统计前缀和出现次数
		}
		return count;
	}
}

560. 和为 K 的数组

class Solution {
    public int subarraySum(int[] nums, int k) {
		int[] s = new int[nums.length + 1];
		for (int i = 1; i < s.length; i++) {
			s[i] = s[i - 1] + nums[i - 1];
		}
		//	统计前缀和每个出现的次数
		Map<Integer, Integer> map = new HashMap<>();
		int count = 0;
		for (int i = 1; i < s.length; i++) {
			if (s[i] == k){  //  当前符合
				count++;
			}
			count += map.getOrDefault(s[i] - k, 0);  //  前方符合
			map.put(s[i], map.getOrDefault(s[i], 0) + 1);	//	逐步放入 map 中
		}

		return count;
	}
}

OD223:数组连续和【res定义为:long 类型】【>= 某个值】

本质:前缀和数组是非递减数组

import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] split = in.nextLine().split(" ");
        int target = Integer.parseInt(split[1]);
        String[] temp = in.nextLine().split(" ");
        int[] arr = new int[temp.length];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = Integer.parseInt(temp[i]);
        }

        long[] sum = new long[temp.length + 1];
        long count = 0;
        for (int i = 1; i < sum.length; i++) {
            sum[i] = sum[i - 1] + arr[i - 1];
            if (sum[i] < target){
                continue;
            }

            if (sum[i] >= target){  //  这个判断可以省略,因为前面已经有 continue了,走到这里的一定是 >= 的
                count++;
            }
            //  临界值:sum[i] - target
            int cur = i - 1;
            while (cur >= 1 && sum[cur] > sum[i] - target){
                cur--;
            }
            count += cur;
        }
        System.out.println(count);
    }
}

OD168. 字符串比较【<= 某个值】

import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String A = in.nextLine();
        String B = in.nextLine();
        int target = Integer.parseInt(in.nextLine());
        int[] arr = new int[A.length()];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = Math.abs(A.charAt(i) - B.charAt(i));
        }

        int[] sum = new int[arr.length + 1];
        int res = 0;
        for (int i = 1; i < sum.length; i++) {
            sum[i] = sum[i - 1] + arr[i - 1];
            if (sum[i] <= target){  //  当前满足,那么减去任意一个数都符合【前缀和是非递减数组】`
                res = Math.max(res, i);
                continue;
            }
            int cur = i - 1;
            while (cur >= 1 && sum[cur] >= sum[i] - target){
                cur--;
            }
            res = Math.max(res, i - cur - 1);   //  当前值不算!!!【因为:sum[i] > target】
        }
        System.out.println(res);
    }
}

OD282. 查找接口成功率最优实践段

import java.util.Scanner;
import java.util.*;


// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int minAverageLost = Integer.parseInt(in.nextLine());
        String[] split = in.nextLine().split(" ");
        int[] arr = new int[split.length];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = Integer.parseInt(split[i]);
        }

        List<Time> list = new ArrayList<>();
        int[] sum = new int[arr.length + 1];
        for (int i = 1; i < sum.length; i++) {
            sum[i] = sum[i - 1] + arr[i - 1];
            int index = 0;
            while (index < i){
                int temp = (int) Math.ceil((sum[i] - sum[index]) / (double)(i - index));
                if (temp <= minAverageLost){
                    list.add(new Time(index, i - 1));   //  不包括开头!!1
                    break;
                }
                index++;
            }
        }

        Collections.sort(list, new Comparator<Time>() {
            @Override
            public int compare(Time o1, Time o2) {
                int len1 = o1.right - o1.left;
                int len2 = o2.right - o2.left;
                if (len1 != len2){
                    return len2 - len1;
                }
                return o1.left - o2.left;
            }
        });
        if (list.size() == 0){
            System.out.println("NULL");
            return;
        }
        int len = list.get(0).right - list.get(0).left;
        StringBuilder res = new StringBuilder();
        for (Time time : list) {
            if (time.right - time.left == len){
                res.append(time.left + "-" + time.right + " ");
            }
        }
        System.out.println(res.toString().trim());
    }
}

class Time{
    int left;
    int right;

    public Time(int left, int right) {
        this.left = left;
        this.right = right;
    }
}

OD189. 分割数组的最大差值

import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int count = Integer.parseInt(in.nextLine());
        long[] arr = new long[count];
        long total = 0;
        for (int i = 0; i < count; i++) {
            arr[i] = in.nextLong();  //  注意类型是 Long,要用 in.nextLong();
            total += arr[i];
        }
        long[] sum = new long[count + 1];
        long res = Long.MIN_VALUE;
        for (int i = 1; i < count; i++) {   //  i = count - 1 时代表除去最后一位的和
            sum[i] = sum[i - 1] + arr[i - 1];
            res = Math.max(res, Math.abs(2 * sum[i] - total));  //  左 - 右
        }
        System.out.println(res);
    }
}

OD130 最长连续子序列

import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
         Scanner in = new Scanner(System.in);
        String[] split = in.nextLine().split(",");
        int target = Integer.parseInt(in.nextLine());
        int[] arr = new int[split.length];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = Integer.parseInt(split[i]);
        }
        int[] sum = new int[arr.length + 1];
        Map<Integer, Integer> map = new HashMap<>();
        int res = -1;
        for (int i = 1; i < sum.length; i++) {
            sum[i] = sum[i - 1] + arr[i - 1];
            if (sum[i] == target){
                res = Math.max(res, i); //  当前符合,这个数之前都符合
            }
            if (map.containsKey(sum[i] - target)){
                res = Math.max(res, i - map.get(sum[i] - target));
            }
            map.putIfAbsent(sum[i], i); //  首次出现的位置
        }

        System.out.println(res);

    }
}

241. 用连续自然数之和来表达整数

import java.util.Scanner;
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
  
    public static void main(String[] args) {
     Scanner in = new Scanner(System.in);
        int num = in.nextInt();
        int[] sum = new int[num + 1];
        Map<Integer, Integer> map = new HashMap<>();
        List<Result> res = new ArrayList<>();
        for (int i = 1; i < sum.length - 1; i++) {
            int now = i - 1;
            sum[i] = sum[i - 1] + now;
            if (map.containsKey(sum[i] - num)){
                res.add(new Result(map.get(sum[i] - num), i));
            }
            map.put(sum[i], i);
        }

        Collections.sort(res, (o1, o2) -> {
            int len1 = o1.end - o1.start;
            int len2 = o2.end - o2.start;
            return len1 - len2;
        });
        System.out.println(num+"="+num);    //  默认肯定有本身【所以最后的 size 也要 + 1】
        res.stream().forEach(result -> {
            StringBuilder sb = new StringBuilder();
            for (int i = result.start; i < result.end; i++) {
                sb.append(i + "+");
            }
            System.out.println(num+"=" + sb.toString().substring(0, sb.length() - 1));
        });
        System.out.println("Result:" + (res.size() + 1));

    }
}

class Result{
    int start;
    int end;

    public Result(int start, int end) {
        this.start = start;
        this.end = end;
    }
}

3. 两数之和

class Solution {
    public int[] twoSum(int[] nums, int target) {
		int[] res = new int[2];
		Map<Integer, Integer> map = new HashMap<>();
		for (int i = 0; i < nums.length; i++) {
			if (map.containsKey(target - nums[i])){	//	map 中有无符合的数
				res[0] = i;
				res[1] = map.get(target - nums[i]);
				break;
			}
			map.put(nums[i], i);
		}
		return res;
    }
}

4. 三数之和

关于 left、right 一起缩进原因:因为第一个数是定死的,后面个数是捆绑的,如果存在一个数,只能由另外一个数才能凑成 0,所以要消除就必须一起消除

class Solution {
	List<Integer> list = new ArrayList<>();
	List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> threeSum(int[] nums) {
    	Arrays.sort(nums);
		List<Integer> temp = new ArrayList<>();

		for (int i = 0; i < nums.length - 2; i++) {
			if (nums[i] > 0){  //  如果第一个数都大于 0了,后面就没有找的必要了
				break;
			}
			if (i > 0 && nums[i] == nums[i - 1]){  # 1. i 去重
				continue;
			}

			int left = i + 1;
			int right = nums.length - 1;
			while (left < right){
				Integer A = nums[i];
				Integer B = nums[left];
				Integer C = nums[right];
				int sum = A + B + C;
				if (sum > 0){
					right--;
				}else if (sum < 0){
					left++;
				}else {
					List<Integer> listTemp = new ArrayList<>();
					listTemp.add(A);
					listTemp.add(B);
					listTemp.add(C);
					res.add(listTemp);
					while (right > left && nums[right - 1] == nums[right]){  //  2. right 去重
						right--;
					}
					while (left < right && nums[left + 1] == nums[left]){  //  3. left 去重
						left++;
					}
					left++;
					right--;
				}
			}
		}
		return res;
	}
}
posted @ 2023-08-31 10:59  爱新觉罗LQ  阅读(2)  评论(0编辑  收藏  举报