[Algorithm]九章六之二: Array

6. Merge Two Sorted Arrays :点击打开链接
class Solution {
    /**
     * @param A and B: sorted integer array A and B.
     * @return: A new sorted integer array
     */
    public int[] mergeSortedArray(int[] A, int[] B) {
        if(A==null || B==null){
            return null;
        }
        int[] result=new int[A.length+B.length];
        int i=0,j=0,index=0;
        
        while(i<A.length && j<B.length){     //两个数组都从头元素一次比较,哪个的当前元素大,result数组里就装哪个
            if(A[i]<B[j]){
                result[index++]=A[i++];      //result数组的索引和两数组之一的索引同步推进
            }else{
                result[index++]=B[j++];
            }
        }
        while(i<A.length){                   //当一个数组全部比较完,只剩下另一个数组的一些元素,也要全部转入result
            result[index++]=A[i++];;
        }
        while(j<B.length){
            result[index++]=B[j++];
        }
        return result;
    }
}
64. Merge Sorted Array:点击打开链接

因为添加或减少一个元素数组整体平移:O(n)

因此添加或减少m个元素而平移:O(m*n),与题O(m+n)不符,因此不能用整体平移

class Solution {
    /**
     * @param A: sorted integer array A which has m elements, 
     *           but size of A is m+n
     * @param B: sorted integer array B which has n elements
     * @return: void
     */
    public void mergeSortedArray(int[] A, int m, int[] B, int n) {  //这题要先理解题意,A有足够空间装所有A和B的元素
        int i=m-1,j=n-1,lastIndex=m+n-1;                            //而且要merge B into A
        while(i>=0 && j>=0){                                        //从后面开始,先放大的,倒着来
            if(A[i]>B[j]){                                          //因为A和Bsorted array,所以不会存在没有地方放的情况
                A[lastIndex--]=A[i--];            
            }else{
                A[lastIndex--]=B[j--];
            }
        }
        
        while(i>=0){
            A[lastIndex--]=A[i--];
        }
        while(j>=0){
            A[lastIndex--]=B[j--];
        }
    }
}
547.Intersection of Two Arrays:点击打开链接
public class Solution {
    /**
     * @param nums1 an integer array
     * @param nums2 an integer array
     * @return an integer array
     */
    public int[] intersection(int[] nums1, int[] nums2) {  //HashSet方法,time:O(n)
        Set<Integer> set=new HashSet<>();
        Set<Integer> intersect=new HashSet<>();
        
        for(int i=0;i<nums1.length;i++){
            if(!set.contains(nums1[i])){
                set.add(nums1[i]);
            }
        }
        
        for(int i=0;i<nums2.length;i++){
            if(set.contains(nums2[i])){
                intersect.add(nums2[i]);
            }
        }
        
        int[] result=new int[intersect.size()];
        int i=0;
        for(Integer num:intersect){
            result[i++]=num;
        }
        return result;
    }
}
public class Solution {
    /**
     * @param nums1 an integer array
     * @param nums2 an integer array
     * @return an integer array
     */
    public int[] intersection(int[] nums1, int[] nums2) {  //Sort arrays方法,time:O(nlogn)
        Arrays.sort(nums1);                          //先sort
        Arrays.sort(nums2);
        
        Set<Integer> set=new HashSet<>();
        
        int i=0,j=0;
        while(i<nums1.length && j<nums2.length){    
            if(nums1[i]<nums2[j]){                  //哪个小哪个向前走一步
                i++;
            }else if(nums[i]>nums2[j]){
                j++;
            }else{                                  //两个相等的时候就加入到set,并且两个同时向前走一步                
                set.add(nums1[i]);    
                i++;
                j++;
            }
        }
        
        int[] result=new int[set.size()];
        int index=0;
        for(Integer num:set){
            result[index++]=num;
        }
        return result;
    }
}
public class Solution {
    /**
     * @param nums1 an integer array
     * @param nums2 an integer array
     * @return an integer array
     */
    public int[] intersection(int[] nums1, int[] nums2) {  //binarySearch方法,time:O(nlogn)
     if (nums1 == null || nums2 == null) {
            return null;
        }
        
        Set<Integer> set = new HashSet<>();
        
        Arrays.sort(nums1);
        for (int i = 0; i < nums2.length; i++) {
            if (binarySearch(nums1, nums2[i])) {
                set.add(nums2[i]);
            }
        }
        
        int[] result = new int[set.size()];
        int index = 0;
        for (Integer num : set) {
            result[index++] = num;
        }
        return result;
    }
    
    private boolean binarySearch(int[] nums,int target){
        if(nums==null || nums.length==0){
            return false;
        }
        int start=0, end=nums.length-1;
        while (start + 1 < end) {
            int mid=(end-start)/2+start;
            if(nums[mid]==target) {
                return true;
            }
            if(nums[mid]<target) {
                start = mid;
            }else {
                end = mid;
            }
        }
        
        if(nums[start]==target) {
            return true;
        }
        if(nums[end]==target) {
            return true;
        }
        return false;
    }
}
548.Intersection of Two ArraysII :  点击打开链接
public class Solution {
    /**
     * @param nums1 an integer array
     * @param nums2 an integer array
     * @return an integer array
     */
    public int[] intersection(int[] nums1, int[] nums2) {  //输出所有的重复元素
        if(nums1==null || nums2==null){
            return null;
        }
        
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        
        List<Integer> temp=new ArrayList<>();             //换成一个list乘装暂时的重复元素,再向数组里倒
        int i=0,j=0;
        while(i<nums1.length && j<nums2.length){
            if(nums1[i]<nums2[j]){
                i++;
            }else if(nums1[i]>nums2[j]){
                j++;
            }else{
                temp.add(nums1[i]);
                i++;
                j++;
            }
        }
        
        int[] result=new int[list.size()];
        int index=0;
        for(Integer num:list){
            result[index++]=num;
        }
        return result;
    }
}
65.Median of Two Sorted Arrays:点击打开链接

1. 如果数组A和B的总长度length是奇数,中位数就是第length / 2 + 1小的数,

    如果length是偶数,中位数就是第length / 2小的数和length / 2 + 1小的数的平均数。

2. 要在两个排序的数组A和B(记成新数组)中找第k小的数,

    我们希望用O(1)的时间把问题分解成:在数组A和数组B中分别找第k / 2小的数。

3. 我们比较数组A中第k / 2小的数和数组B中第k / 2小的数:

    如果A[k / 2 - 1] < B[k / 2 - 1],说明在新数组中第k小的数不可能是A[k/2 - 1]以及这个数之前的数字, 

    那么我们可以把这k / 2个数字从A数组中踢掉,并在B数组和 过数的A数组里    分别找第k / 2小的数

    同理,如果B[k / 2 - 1] < A[k / 2 - 1],我们可以把k / 2个数字从B数组中踢掉,并在A数组和踢过数的B数组里分别找第k / 2小的数。

class Solution {
    /**
     * @param A: An integer array.
     * @param B: An integer array.
     * @return: a double whose format is *.5 or *.0
     */
    public double findMedianSortedArrays(int[] A, int[] B) {
        int length=A.length+B.length;
        if(length%2==0){
            return (findKth(A,0,B,0,length/2)+findKth(A,0,B,0,length/2+1))/2.0;
        }
        return findKth(A,0,B,0,length/2+1);
    }
    private int findKth(int[] A,int startA,int[] B,int startB,int k){
        if(startA>=A.length){                                                //如果A变成null,就成了B数组单独找Kth
            return B[startB+k-1];
        }
        if(startB>=B.length){                                                //如果B变成null,就成了A数组单独找Kth
            return A[startA+k-1];
        }
        if(k==1){                                                            //如果找第一大的数,就是A,B数组中的第一个小值
            return Math.min(A[startA],B[startB]);
        }
        
        int valueA=startA+k/2-1<A.length?A[startA+k/2-1]:Integer.MAX_VALUE;  //哪个数组不够了,就用无穷大后面补全
        int valueB=startB+k/2-1<B.length?B[startB+k/2-1]:Integer.MAX_VALUE;
        if(valueA<valueB){                                                   
            return findKth(A,startA+k/2,B,startB,k-k/2);
        }
        return findKth(A,startA,B,startB+k/2,k-k/2);
    }
}
41. Mixmam Subarray:点击打开链接

PrefixSum[i]=nums[0]+nums[1]+...+nums[i-1],PrefixSum[0]=0;

例如:int [ ] num={1,2,3,4,-5}

PrefixSum[0]=0,

PrefixSum[1]=nums[0]=1;

PrefixSum[2]=nums[0]+nums[1]=1+2=3;

PrefixSum[3]=nums[0]+nums[1]+nums[2]=1+2+3=6;

PrefixSum[4]=nums[0]+nums[1]+nums[2]+nums[3]=1+2+3+4=10;

PrefixSum[5]=nums[0]+nums[1]+nums[2]+nums[3]+nums[4]=1+2+3+4+(-5)=5;

public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A integer indicate the sum of max subarray
     */
    public int maxSubArray(int[] nums) {
        if(nums==null || nums.length==0){
            return 0;
        }
        
        int sum=0;
        int maxVal=Integer.MIN_VALUE;
        int minSum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
            maxVal=Math.max(maxVal,sum-minSum);    //每次拿到一个当前最大值,都要比较(当前最大值)与(当前sum-当前最小和)的小大
            minSum=Math.min(minSum,sum);           //如果当前sum-当前最小和,自然得到就是当前最大值
        }
        return maxVal;
    }
}
42. Maximum SubArray II: 点击打开链接
public class Solution {
    /**
     * @param nums: A list of integers
     * @return: An integer denotes the sum of max two non-overlapping subarrays
     */
    public int maxTwoSubArrays(ArrayList<Integer> nums) {
        int maxVal=Integer.MIN_VALUE;
        int minSum=0;
        int sum=0;
        int[] left=new int[nums.size()];
        for(int i=0;i<nums.size();i++){                   //左边开始相加,left[i]表示到i当前的最大值
            sum+=nums.get(i);
            maxVal=Math.max(maxVal,sum-minSum);
            minSum=Math.min(sum,minSum);
            left[i]=maxVal;
        }
        
        maxVal=Integer.MIN_VALUE;
        minSum=0;
        sum=0;
        int[] right=new int[nums.size()];
        for(int i=nums.size()-1;i>=0;i--){                //右边开始相加,right[i]表示到i当前的最大值
            sum+=nums.get(i);
            maxVal=Math.max(maxVal,sum-minSum);
            minSum=Math.min(sum,minSum);
            right[i]=maxVal;
        }
        
        maxVal=Integer.MIN_VALUE;
        for(int i=0;i<nums.size()-1;i++){
            maxVal=Math.max(maxVal,left[i]+right[i+1]);  //最后对每一个左边最大,与比它向后一个位置的右边最大的和取最大
        }
        return maxVal;
    }
}
138.Subarray Sum:点击打开链接

思路:子数组和为一个数,无非就是两种情况,从头开始的subarray,和从中间某一个位置开始的subarray

         对于从中间某一位置i开始的subarray,例如前i位置之和为3,而从i+1 ~ j这一段加起来还是3,说明i+1 ~ j这段和为0

注意:如果需要计算子数组从下标i到下标j之间的所有数之和,则有:Sum(i~j)=PrefixSum[j+1]-PrefixSum[i]

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) {                          //方法一
        ArrayList<Integer> result=new ArrayList<>();
        if(nums==null || nums.length==0){
            return result;
        }
        
        Map<Integer,Integer> map=new HashMap<>();
        int sum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
            if(!map.containsKey(sum)){                 //从头开始的每一个preSum
                map.put(sum,i);
                if(sum==0){
                   result.add(0); 
                   result.add(i);
                   break;
                }   
            }else{                                     //非从头开始(中间段)的每一个preSum
                result.add(map.get(sum)+1);
                result.add(i);
                break;
            }
        }
        return result;
    }
}

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) {                          //方法二:同样思路
        ArrayList<Integer> ans = new ArrayList<Integer>();
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(0, -1);                                   //先放入sum为0,位置为-1
      
        int sum = 0;
        for (int i = 0; i <nums.length; i++) {
            sum += nums[i];
            if (map.containsKey(sum)) {                   //有同样的sum出现,就取之前出现sum的前一个位置和当前sum位置      
                ans.add(map.get(sum) + 1);
                ans.add(i);
                return ans;
            }
            map.put(sum, i);                              //只要有新的sum就放入到sum和位置i,表示从0开始到i的这段sum
        }
        return ans;
    }
}

560. Subarray Sum Equals K:点击打开链接
public class Solution {
    public int subarraySum(int[] nums, int k) {               
        if(nums==null || nums.length==0){
            return 0;
        }
        
        Map<Integer,Integer> map=new HashMap<>();
        int result=0;
        int sum=0;
        
        map.put(0,1);                                     //考虑到从头开始的情况,要先放入sum为0,次数为1,不然会空指针异常
        for(int i=0;i<nums.length;i++){  
            sum+=nums[i];
            if(map.containsKey(sum-k)){                   //每到一个数
                result+=map.get(sum-k);
            }
            map.put(sum,map.getOrDefault(sum,0)+1);       //用map来保存当前数组从头开始的前i项和的次数
        }
        return result;
    }
}

public class Solution {
    public int subarraySum(int[] nums, int k) {           //brute force方法
        if(nums==null || nums.length==0){
            return 0;
        }
        
        int count=0;
        for(int i=0;i<nums.length;i++){
            int sum=0;
            sum+=nums[i];
            if(sum==k){
                count++;
            }
            for(int j=i+1;j<nums.length;j++){
                sum+=nums[j];
                if(sum==k){
                    count++;
                }
            }
        }
        return count;
    }
}
139.Subarray Sum Closet: 点击打开链接
思路: 如果需要计算子数组从下标i到下标j之间的所有数之和, 则有:Sum(i~j)=PrefixSum[j+1]-PrefixSum[i]
          本题只要不断更新使Sum(i~j)尽可能接近0
class Pair {
    int sum;
    int index;
    public Pair(int sum, int index) {
        this.sum = sum;
        this.index = index;
    }
}
    
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) {
        int[] result=new int[2];
        if(nums==null || nums.length==0){
            return result;
        }
        
        int len=nums.length;
        if(len==1){
            result[0]=result[1]=0;
        }
        
        Pair[] preSum=new Pair[len+1];                       //preSum表示的是前i个元素和,和对应的索引i-1
        int pre=0;                                           //也就是preSum[3],前3个元素和,是0,1,2,因此索引是2
        preSum[0]=new Pair(0,0);
        for(int i=1;i<=len;i++){                             //for循环拿到前i个元素和
            preSum[i]=new Pair(pre+nums[i-1],i);
            pre=preSum[i].sum;
        }
        
        Arrays.sort(preSum,new Comparator<Pair>(){           //然后重新排序preSum,按照和的大小
            public int compare(Pair p1,Pair p2){             //因此重新排序后preSum表示的在数组preSum中第几大
                return p1.sum-p2.sum;                       
            }
        });
        
        int closet=Integer.MAX_VALUE;
        for(int i=1;i<=len;i++){
            if(preSum[i].sum-preSum[i-1].sum<closet){        //两两一次遍历记录当前最小的差,也就是对应的索引差最接近0
                closet=preSum[i].sum-preSum[i-1].sum;
                int[] temp=new int[]{preSum[i-1].index-1,preSum[i].index-1};
                Arrays.sort(temp);
                result[0]=temp[0]+1;
                result[1]=temp[1];
            }
        }
        return result;
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值