子数组问题

一般思路:把当前数作为子数组的最后一个数

给定一个数组arr,和一个整数num,求在arr中,累加和等于num的最长子数组的长度

例子:
arr = {7,3,2,1,1,7,7,7} num = 7
其中有很多的子数组累加和等于7,但是最长的子数组是{3,2,1,1},所
以返回其长度4

思路:按住一个位置,找到以这个位置结尾的最长子数组。
用map记录从位置0开始的累加和与该累加和第一次出现的位置,那么当遍历到一个位置时,只要在map中找是否有 sum-num,如果有的话就是从map.get(sum-num)到该位置的长度。
举例:当遍历到1000时,从0到1000的累加和为2000,如果我们要找800这个累加和,那么只要找到1200第一次出现的位置x,那么x~1000的子数组累加和就是800。

public static int maxLength(int[] arr, int k) {
    if (arr == null || arr.length == 0) {
        return 0;
    }
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
    map.put(0, -1); // important
    int len = 0;
    int sum = 0;
    for (int i = 0; i < arr.length; i++) {
        sum += arr[i];
        if (map.containsKey(sum - k)) {
            len = Math.max(i - map.get(sum - k), len);
        }
        if (!map.containsKey(sum)) {
            map.put(sum, i);
        }
    }
    return len;
}

定义数组的异或和的概念:

数组中所有的数异或起来,得到的结果叫做数组的异或和,
比如数组{3,2,1}的异或和是,321 = 0
给定一个数组arr,你可以任意把arr分成很多不相容的子数组,你的目的是:
分出来的子数组中,异或和为0的子数组最多。
请返回:分出来的子数组中,异或和为0的子数组最多是多少?

思路:dp,用map记录异或和为sum的最晚出现的位置k,那么如果0i的异或和为sum,则ki的异或和为0(sum^0=sum)
dp[i]=dp[i-1] (以i为末尾不是异或和为0的子数组)
dp[i] =dp[k-1]+1
取其中较大的值

public static int mostEOR(int[] arr) {
    int ans = 0;
    int xor = 0;
    int[] mosts = new int[arr.length];
    HashMap<Integer, Integer> map = new HashMap<>();
    map.put(0, -1);
    for (int i = 0; i < arr.length; i++) {
        xor ^= arr[i];
        if (map.containsKey(xor)) {
            int pre = map.get(xor);
            mosts[i] = pre == -1 ? 1 : (mosts[pre] + 1);
        }
        if (i > 0) {
            mosts[i] = Math.max(mosts[i - 1], mosts[i]);
        }
        map.put(xor, i);
        ans = Math.max(ans, mosts[i]);
    }
    return ans;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容