Array中的subarray问题

来源:互联网 发布:软件项目质量管理问题 编辑:程序博客网 时间:2024/06/07 00:07

该题型多采用prefixSum的方法:

(一)Maximum Subarray (Frequent ++)

http://www.lintcode.com/en/problem/maximum-subarray/

题目:找到数组中总和最大的子集并返回该子集总和;

解答:将该数组的prefixSum存储在新数组中(亦可覆盖原数组节省空间),因为sum(i ~ j) = prefixSum(j + 1)  - prefixSum(i),遍历prefixSum数组, 用当前元素减去已知最小元素依次比较得到结果;

改进:可以把求prefixSum的循环和找最大的循环合并成一个

代码:

public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A integer indicate the sum of max subarray
     */
    public int maxSubArray(int[] nums) {
        // write your code
        int len = nums.length;
        int[] prefixSum = new int[len];
        int sum = 0;
        for (int i = 0; i < len; i++) {
            sum += nums[i];
            prefixSum[i] = sum;
        }
        int res = nums[0];
        int min = 0;
        for (int i = 0; i < len; i++) {
            int tempSum = prefixSum[i] - min;
            res = tempSum > res ? tempSum : res;
            min = prefixSum[i] < min ? prefixSum[i] : min;
        }
        return res;
    }
}


(二)Subarray Sum

http://www.lintcode.com/en/problem/subarray-sum/

题目:找到和为零的子集并返回子集的始末位置;

第一次犯错:忘记考虑[0]的情况;
第二次犯错:时间复杂度高,超时;

解答:采用Hashmap的形式存储prefixSum;

代码:
public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A list of integers includes the index of the first number 
     *          and the index of the last number
     */
    public ArrayList<Integer> subarraySum(int[] nums) {
        // write your code here
        ArrayList<Integer> res = new ArrayList<Integer>();
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            if (sum == 0) {
                res.add(0);
                res.add(i);
                break;
            }
            if (map.containsKey(sum)) {
                res.add(map.get(sum) + 1);
                res.add(i);
                break;
            } else {
                 map.put(sum, i);
            }
        }
        return res;
    }
}

(三)Subarray Sum closest 

http://www.lintcode.com/en/problem/subarray-sum-closest/

题目:找出数组中子集和最接近0的首、尾index;

解答:将序列index和对应的prefixSum存在map中,将prefixSum单独存在一个序列里,将该序列排序,依次比较相邻元素将差值较小的元素序列号提取出来,比较大小,依次更新res[0]和res[1]。

第一次犯错:时间复杂度太高,超时;

第二次犯错:使用map,prefixSum相同的元素会覆盖,导致结果错误;
解答:当prefixSum存在相同元素时,说明存在子数列和为0,故无需覆盖,直接返回首位值即可;

第三次犯错:单独把最后一个元素加入map时,忘记判断该元素是否已存在于序列中(循坏未覆盖,需单独判断)

代码:
public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A list of integers includes the index of the first number 
     *          and the index of the last number
     */
    public int[] subarraySumClosest(int[] nums) {
        // write your code here
        int[] res = new int[2];
        int[] prefixSum = new int[nums.length + 1];
        int diff = Integer.MAX_VALUE;
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; i++) {
           prefixSum[i + 1] = prefixSum[i] + nums[i];
           if (!map.containsKey(prefixSum[i])) {
               map.put(prefixSum[i], i);
            } else {
                res[0] = map.get(prefixSum[i]);
                res[1] = i - 1;
                return res;
            }
        }
        
        if (!map.containsKey(prefixSum[nums.length])) {
            map.put(prefixSum[nums.length], nums.length);
        } else {
            res[0] = map.get(prefixSum[nums.length]);
            res[1] = nums.length - 1;
            return res;
        }
        
        Arrays.sort(prefixSum);
        for (int i = 1; i < nums.length + 1; i++) {
            if (prefixSum[i] - prefixSum[i - 1] < diff) {
                int i1 = map.get(prefixSum[i]);
                int i2 = map.get(prefixSum[i - 1]);
                diff = prefixSum[i] - prefixSum[i - 1];
                res[0] = Math.min(i1, i2);
                res[1] = Math.max(i1, i2) - 1;
            }
        }
        return res;
    }
}


原创粉丝点击