[Algorithm]九章七:Two Pointer

604. Window Sum:点击打开链接

例如:[1,2,7,8,5], k=3

sum[0]=nums[0]+nums[1]+nums[2]=10

sum[1]=sum[0]-nums[0]+nums[0+3]=17,也就是说sum[1]=10-1+8

sum[2]=sum[1]-nums[1]+nums[1+3]=20,也就是说sum[2]=17-2+5

窗口向后滑动,要减去(滑出窗口里的值),同时加上(滑入窗口里的值)

 

public class Solution {
    /**
     * @param nums a list of integers.
     * @return the sum of the element inside the window at each moving.
     */
    public int[] winSum(int[] nums, int k) {
        if(nums==null || nums.length==0){
            return new int[0];
        }
        if(k<=0){
            return new int[0];
        }
        
        int[] sum=new int[nums.length-k+1];               
        for(int i=0;i<k;i++){                                //i<k
             sum[0]+=nums[i];
        }
        for(int i=1;i<sum.length;i++){                       //i<sum.length,不然数组越界异常
            sum[i]=sum[i-1]-nums[i-1]+nums[i-1+k];
        }
        return sum;
    }
}

539. Move Zeros:点击打开链接

public class Solution {
    /**
     * @param nums an integer array
     * @return nothing, do this in-place
     */
    public void moveZeroes(int[] nums) {
        int j=0;
        for(int i=0;i<nums.length;i++){     //i从头开始遍历,当值不为0就和第一个交换位置,再有值不为0,和第一个的后一个交换
            if(nums[i]!=0){                 //即使开始的值不为0,也不影响,因为相当于自己和自己交换
                int temp=nums[i];           //例如:[1,2,0,3,4],开始交换的时候1,2的位置不变,值为3的时候和0交换,4同理
                nums[i]=nums[j];
                nums[j]=temp;
                j++;
            }
        }
    }
}
public class Solution {
    /**
     * @param nums an integer array
     * @return nothing, do this in-place
     */
    public void moveZeroes(int[] nums) {    //为什么这种做法不行?
        int j=nums.length;                  //i从头开始遍历,当值为0就和最后一个数交换位置,再有值为0,和最后一个的前一个交换
        for(int i=0;i<nums.length;i++){     //因为这种做法可能最后一个位置的值是0
            if(nums[i]==0){                 //例如:[0,1,0,1,3,0],开始交换的时候只是头和尾两个0交换了位置,所以不对 
                int temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
                j--;
            }
        }
    }
}

521.Remove Duplicates from Sorted Array:点击打开链接

 

public class Solution {
    /**
     * @param nums an array of integers
     * @return the number of unique integers
     */
    public int deduplication(int[] nums) {   //例如:[1,3,1,4,4,2]
        if(nums==null || nums.length==0){
            return 0;
        }
        
        Arrays.sort(nums);                   //[1,1,1,2,3,4,4]            
        int index=1;
        for(int i=1;i<nums.length;i++){      //就让第一个值不动,从第二个值开始,依次与前一个值比较
            if(nums[i]!=nums[i-1]){          //如果两者不相等,后者值和index++位置的值交换位置
                nums[index++]=nums[i];
            }
        }
        return index;
    }
}

 

 

public class Solution {
    /**
     * @param nums an array of integers
     * @return the number of unique integers
     */
    public int deduplication(int[] nums) {  //方法二
        if(nums==null || nums.length==0){
            return 0;
        }
        
        Arrays.sort(nums);                  //解题前要看题目给出的数组是不是有序数组,不是的话要排序
        int i=0;                            //是否排序也要看题目要求,如果让输出符合条件的索引,不可以排序
        for(int n:nums){
            if(i<1 || n!=nums[i-1]){
                nums[i++]=n;
            }
        }
        return i;
    }
}

101. Remove Duplicates from Sorted Array II:点击打开链接

 

思路:当i=0时,nums[0]还是本身

         当i=1时,nums[1]也还是本身,因为不管nums[1]是否等于nums[0]都没关系,因为题目说最多可以有两个duplicates

         从i=2开始,开始判断nums[i-2]!=n,也就是说nums[0]!=nums[2],其实就是判断这个数与否等于它前两位的那个数,

         如果不等于,符合题目要求,当前数有效,不移除。

public class Solution {
    /**
     * @param A: a array of integers
     * @return : return an integer
     */
    public int removeDuplicates(int[] nums) {
        if(nums==null || nums.length==0){
            return 0;
        }
                                                         
        int i=0;                                         //例如{3,3,4,5,5,6}
        for(int n:nums){                                 //在i=0,i=1的时候已经和数组用n表示的前两个数比较过
            if(i<2 || n!=nums[i-2]){                     //i=2的时候,n!=nums[i-2]表示的是4!=nums[0]
                nums[i++]=n;                            
            }
        }
        return i;
    }
}

 

8.Rotate String:点击打开链接

例如:char[] str=[a,b,c,d,e,f,g],offset=3

         Output:    [e,f,g,a,b,c,d]

三步翻转法:

1. [g,f,e,d,c,b,a],整个大翻转

2. [e,f,g,d,c,b,a], e,f,g翻转

3. [e,f,g,a,b,c,d], a,b,c,d翻转

注意:先整个大翻转的必要性,一般来说,由于往前放的位数少,因此先进行整个大翻转会省时

        当然也可以先局部翻转,再整个大翻转

        要看具体题目要求,是要在原来有序的数组上后面几个元素翻转到前面,还是已经翻转好的要恢复有序数组

        也就是说,是要[a,b,c,d,e,f,g]->[e,f,g,a,b,c,d],还是[e,f,g,a,b,c,d]恢复成[a,b,c,d,e,f,g]

 

public class Solution {
    /**
     * @param str: an array of char
     * @param offset: an integer
     * @return: nothing
     */
    public void rotateString(char[] str, int offset) {
        if(offset==0){
            return;
        }
        
        if(str==null || str.length==0){
            return;
        }
        
        int n=str.length;
        offset=offset%n;
        reverse(str,0,n-1);
        reverse(str,0,offset-1);
        reverse(str,offset,n-1);
    }
    
    private void reverse(char[] str,int start,int end){
        while(start<end){
            char temp=str[start];   //char temp
            str[start]=str[end];                       
            str[end]=temp;
            start++;
            end--;
        }
    }
}

39.Recover Rotated Sorted Array :点击打开链接

题意:这题就是要恢复成有序arraylist,例如:[4,5,1,2,3]->[1,2,3,4,5]

思路:从5和1这个位置入手,遍历整个list的值,只要前一个值比后一个值大,就找到了5和1,然后j进行三步翻转

注意:reverse方法对一个arraylist进行reverse,因此用了方法arraylist.set()

public class Solution {
    /**
     * @param nums: The rotated sorted array
     * @return: void
     */
    public void recoverRotatedSortedArray(ArrayList<Integer> nums) {
        if(nums==null || nums.size()==0){
            return;
        }
        
        int k=0;
        for(int i=0;i<nums.size()-1;i++){
            if(nums.get(i)>nums.get(i+1)){
                k=i;
                reverse(nums,0,k);
                reverse(nums,k+1,nums.size()-1);
                reverse(nums,0,nums.size()-1);
            }
        }
    }
    
    private void reverse(ArrayList<Integer> nums,int start,int end){
        while(start<end){
            int temp=nums.get(start);
            nums.set(start,nums.get(end));    //nums.set()
            nums.set(end,temp);
            start++;
            end--;
        }
    }
}

56.Two Sum:点击打开链接

下面就是经典题型Two Sum和它的一系列follow ups

对于Two Sum一般有两种做法:HashMap和Two Pointers

public class Solution {
    /*
     * @param numbers : An array of Integer
     * @param target : target = numbers[index1] + numbers[index2]
     * @return : [index1 + 1, index2 + 1] (index1 < index2)
     */
    public int[] twoSum(int[] numbers, int target) {       //HashMap方法
        int[] result=new int[2];
        if(numbers==null ||numbers.length==0){
            return result;
        }
        
        Map<Integer,Integer> map=new HashMap<>();          //例如:[2,7,11,15],target=9
        for(int i=0;i<numbers.length;i++){
            if(!map.containsKey(target-numbers[i])){       //遍历数组,一开始nums[0]=2,map里没有7,放入<2,0>
                map.put(numbers[i],i);
            }else{                                         //往下遍历到nums[1]=7,map里有2,
                result[0]=map.get(target-numbers[i])+1;    //就把2和7所对应的索引加入到result list里
                result[1]=i+1;                             //由于题目要求result不是zero-based,所以每个索引值+1
            }
        }
        return result;
    }
}

608.Two Sum-Input array is Sorted:点击打开链接

 

public class Solution {
    /*
     * @param nums an array of Integer
     * @param target = nums[index1] + nums[index2]
     * @return [index1 + 1, index2 + 1] (index1 < index2)
     */
    public int[] twoSum(int[] nums, int target) {         //双指针法:适合可以sort的数组
        int[] result=new int[2];
        if(nums==null || nums.length==0){
            return result;
        }
        
        int start=0;
        int end=nums.length-1;
        while(start<end){                                 //因为最后要有start和end两个数,因此不能start<=end
            if(nums[start]+nums[end]<target){   
                start++;
            }else if(nums[start]+nums[end]>target){
                end--;
            }else{
                result[0]=start+1;                        //注意好题目要求是non zero-based,还是zero-based
                result[1]=end+1;
                return result;
            }
        }
        return null;
    }
}

607.Two Sum-Data Structure Design:点击打开链接

 

public class TwoSum {                                    //只能使用HashMap的
    private List<Integer> list=null;
    private Map<Integer,Integer> map=null;
    public TwoSum(){
        list=new ArrayList<>();
        map=new HashMap<>();
    }
    // Add the number to an internal data structure.
    public void add(int number) {
        // Write your code here
        if(!map.containsKey(number)){
            map.put(number,1);
            list.add(number);
        }else{
            map.put(number,map.get(number)+1);
        }
    }

    // Find if there exists any pair of numbers which sum is equal to the value.
    public boolean find(int value) {
        for(int i=0;i<list.size();i++){
            int nums1=list.get(i);
            int nums2=value-nums1;
            if(nums1==nums2 && map.get(nums1)>1){
                return true;
            }
            if(nums1!=nums2 && map.containsKey(nums2)){
                return true;
            }
        }
        return false;
    }
}

// Your TwoSum object will be instantiated and called as such:
// TwoSum twoSum = new TwoSum();
// twoSum.add(number);
// twoSum.find(value);

 

587.Two Sum-Unique pairs:点击打开链接

public class Solution {
    /**
     * @param nums an array of integer
     * @param target an integer
     * @return an integer
     */
    public int twoSum6(int[] nums, int target) {
        if(nums==null || nums.length<0){
            return 0;
        }
        
        Arrays.sort(nums);
        int start=0,end=nums.length-1;
        int count=0;
        while(start<end){
            if(nums[start]+nums[end]==target){
                start++;
                end--;
                count++;                                          
                while(start<end && nums[start]==nums[start-1]){   //当有一对和为target的数时,看start的后面的数是否与start等
                    start++;                                      //如果等,就要往前走以便略过这个相同的数
                }
                while(start<end && nums[end]==nums[end+1]){       //也要看end的前面的数时候与end等
                    end--;                                        //如果等,就要end--方式向前走以便略过这个相同的数
                }
            }else if(nums[start]+nums[end]>target){
                end--;
            }else{
                start++;
            }
        }
        return count;
    }
}

609. Two Sum-Less than or equal to target: 点击打开链接

例如:[2,7,11,15],target=24

思路:当2+15<24,15是最大值都小于target了,2+7,2+11一定也小于,两数对应的索引相减3-0=3,这段区间有3对数符合要求,start++

         再看[2,7,11,15]这段区间,同理有3-1=2对数符合要求,start++

         再看[2,7,11,15]这段区间, 11+15>target,end--      

 

public class Solution {
    /**
     * @param nums an array of integer
     * @param target an integer
     * @return an integer
     */
    public int twoSum5(int[] nums, int target) {
        if(nums==null || nums.length==0){
            return 0;
        }
        
        Arrays.sort(nums);
        
        int count=0;
        int start=0,end=nums.length-1;
        while(start<end){
            if(nums[start]+nums[end]<=target){
                count+=end-start;
                start++;
            }else{
                end--;
            }
        }
        return count;
    }
}

443.Two Sum-Greater than target:点击打开链接

 

public class Solution {
    /**
     * @param nums: an array of integer
     * @param target: an integer
     * @return: an integer
     */
    public int twoSum2(int[] nums, int target) {   //和小于等于target的正好相反
        if(nums==null ||nums.length==0){
            return 0;
        }
        
        Arrays.sort(nums);
        
        int count=0;
        int start=0,end=nums.length-1;
        while(start<end){
            if(nums[start]+nums[end]<=target){     //如果小于等于target,start++
                start++;
            }else{                                 //直到大于target,这段区间符合条件的对数是:区间前后索引之差        
                count+=end-start;
                end--;                             //end--
            }
        }
        return count;
    }
}

610.Two Sum-Difference equals to target:点击打开链接

例如:[2,7,15,14],target=5

思路:遍历数组,但是每个值都要查看nums[i]+targetnums[i]-target 两种情况      

 

public class Solution {
    /*
     * @param nums an array of Integer
     * @param target an integer
     * @return [index1 + 1, index2 + 1] (index1 < index2)
     */
    public int[] twoSum7(int[] nums, int target) {
        int[] result=new int[2];
        if(nums==null || nums.length==0){
            return result;
        }
        
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            int diff1=nums[i]-target;
            int diff2=nums[i]+target;
            if(!map.containsKey(diff1) && !map.containsKey(diff2)){
                map.put(nums[i],i);
            }else if(map.containsKey(diff1)){
                result[0]=map.get(diff1)+1;
                result[1]=i+1;
                break;
            }else if(map.containsKey(diff2)){
                result[0]=map.get(diff2)+1;
                result[1]=i+1;
                break;
            }
        }
        return result;
    }
}

57. 3Sum:点击打开链接

例如:[-1,0,1,2,-1,-4]

思路:a+b+c=0,-a=b+c

         遍历数组里的每一个数nums[i],对于每一个数,都从i+1~nums.length-1区间来找另外两个数,

         使得-nums[i]=nums[i+1]+nums[nums.length-1],也就是nums[i]+nums[i+1]+nums[nums.length-1]=0

注意:1. 用Two Pointers方法一定要先Arrays.sort()数组     

          2. 对于nums[i],nums[i+1]和nums[length-1]都要判断是不是与前一个数相等 

 

public class Solution {
    /**
     * @param numbers : Give an array numbers of n integer
     * @return : Find all unique triplets in the array which gives the sum of zero.
     */
    public ArrayList<ArrayList<Integer>> threeSum(int[] numbers) {
        ArrayList<ArrayList<Integer>> result=new ArrayList<>();
        if(numbers==null || numbers.length<3){                 //只要numbers.length<3就不符合题意了
            return result;
        }
        
        Arrays.sort(numbers);
        for(int i=0;i<numbers.length-1;i++){
            if(i>0 && numbers[i]==numbers[i-1]){               //对于每一个a都要判断是不是和前一个相等
                continue;
            }
            int target=-numbers[i];
            int start=i+1;
            int end=numbers.length-1;
            twoSum(numbers,start,end,target,result);
        }
        return result;
    }
    
    private void twoSum(int[] nums,int start,int end,int target,ArrayList<ArrayList<Integer>> result){
        while(start<end){
            if(nums[start]+nums[end]==target){
                ArrayList<Integer> list=new ArrayList<>();
                list.add(-target);
                list.add(nums[start]);
                list.add(nums[end]);
                result.add(list);
                start++;
                end--;
                
                while(start<end && nums[start]==nums[start-1]){     
                    start++;
                }
                while(start<end && nums[end]==nums[end+1]){
                    end--;
                }
            }else if(nums[start]+nums[end]<target){
                start++;
            }else{
                end--;
            }
        }
    }
}

 

例如:[1,1,2,3,4,5,6],target=9

          1. i从0向后遍历

          2. 第一轮i=0,start=1,end=6,因为开始小于9,所以start++到start=2,此时1+2+6=9,

              完成装到result后,start和end还会移动,找其他满足条件的组合,以上是一个完整的第一轮,然后才开始第二轮

          3. 第二轮i=1,start=1,end=6,此时1+2+6=9

              因为被遍历的i与它前一个数相等,因此会以continue的方法跳出本次,因为这样的情况下会输出重复组合

          4. 第三轮i=2

public class Solution {
    /**
     * @param numbers : Give an array numbers of n integer
     * @return : Find all unique triplets in the array which gives the sum of zero.
     */
    public ArrayList<ArrayList<Integer>> threeSum(int[] numbers) {       //方法二:直接看当前三个数的和是不是等于0
        ArrayList<ArrayList<Integer>> result=new ArrayList<>();          //个人感觉这个方法更直接,更容易弄懂
        if(numbers==null || numbers.length<3){
            return result;
        }
        
        Arrays.sort(numbers);
        for(int i=0;i<numbers.length-1;i++){
            if(i>0 && numbers[i]==numbers[i-1]){                         //如果i重复
                continue;                                                //跳出本次i,进入for循环里的下一个i
            }
            int start=i+1;
            int end=numbers.length-1;
            while(start<end){
                int sum=numbers[i]+numbers[start]+numbers[end];
                if(sum==0){
                    ArrayList<Integer> list=new ArrayList<>();
                    list.add(numbers[i]);
                    list.add(numbers[start]);
                    list.add(numbers[end]);
                    result.add(list);
                    start++;
                    end--;
                    while(start<end && numbers[start]==numbers[start-1]){//如果start重复
                        start++;
                    }
                    while(start<end && numbers[end]==numbers[end+1]){    //如果end重复
                        end--;
                    }
                }else if(sum<0){
                    start++;
                }else{
                    end--;
                }
            }
        }
        return result;
    }
}

923. 3Sum With Multiplicity

 public int threeSumMulti(int[] A, int target) {
        int mol = 1000000007; // 如果写成10^9+7的形式,就过不了,Bitwise Operators 
        Arrays.sort(A);
        int res = 0;
        Map<Integer, Long> map = new HashMap<>();
        for (int i = 0; i < A.length; ++i) {
            map.put(A[i], map.getOrDefault(A[i], 0l) + 1l);
        }
       
        
        for (int i = 0; i < A.length; i++) {
            if (i > 0 && A[i] == A[i - 1]) 
            {
                continue;
            }
            int start = i + 1, end = A.length - 1;
            
            while (start < end) {
                if (A[i] + A[start] + A[end] < target) {
                    start++;
                }
                else if (A[i] + A[start] + A[end] > target) {
                    end--;
                }
                else {
                    if (A[i] == A[start] && A[start] == A[end]) {
                        res += (map.get(A[i])) * (map.get(A[i]) - 1) * (map.get(A[i]) - 2) / 6 % mol;
                    }
                    else if (A[i] == A[start]) {
                        res += (map.get(A[i])) * (map.get(A[i]) - 1) / 2 * (map.get(A[end])) % mol;
                    }
                    else if (A[start] == A[end]) {
                        res += (map.get(A[i])) * (map.get(A[start])) * (map.get(A[start]) - 1) / 2 % mol;
                    }
                    else {
                        res += map.get(A[i]) * map.get(A[start]) * map.get(A[end]) % mol;
                    }
                    
                    start++;
                    end--;
                    while (start<end && A[start] == A[start-1])
                    {
                        start++;
                    }
                    while (start<end && A[end] == A[end+1]) 
                    {
                        end--;
                    }                  
                }
            }
        }
        return res;

259. 3Sum Smaller

Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < nthat satisfy the condition nums[i] + nums[j] + nums[k] < target.

Example:

Input: nums = [-2,0,1,3], and target = 2
Output: 2 
Explanation: Because there are two triplets which sums are less than 2:
             [-2,0,1]
             [-2,0,3]

Note: 以[-2, 0, 1, 3]作为example , nums[i] =-2,,nums[start]=0,,nums[end]=3,,当-2+0+3<target时,如果采用start++来判断, 此时nums[start]=1, 所以走向一直是start向右移动,会漏掉end应该向左移动的cases

class Solution {
    public int threeSumSmaller(int[] nums, int target) {
        
        int result = 0;
        if(nums==null || nums.length == 0)
        {
            return result;
        }
        
        Arrays.sort(nums);
        
        for(int i=0; i<nums.length-1; i++)
        {
            int start= i+1;
            int end= nums.length-1;
                    
            while(start < end)
            {
                if(nums[i] + nums[start] + nums[end] < target )
                {                    
                    int count = end-start;  //这边不能一个一个走,原因是只单向移动start,会漏掉end符合条件的情况
                    result += count;
                    start++;
                }
                else
                {
                    end--;
                }            
            }
        }     
        return result;
    }
}

382.Triangle Count:点击打开链接

例如:[3,4,6,7],Output:3

思路:sort数组后,i从后向前遍历数组,遍历的值nums[i]作为第三条边a,而nums[0]和nums[i-1]作为另两边b,c

         因此如果满足b+c>a,就是一个三角形。

         同时要注意,如果此时的b+c>a,得知(b后面的数)+c>a一定成立,所以直接加上这一段的有效三角形个数,然后end--;

         如果b+c<a,就start++;

注意:此题的遍历方向         

public class Solution {
    /**
     * @param S: A list of integers
     * @return: An integer
     */
    public int triangleCount(int S[]) {
        if(S==null || S.length<3){
            return 0;
        }
        
        Arrays.sort(S);
        
        int count=0;
        for(int i=S.length-1;i>0;i--){            //数组从后往前倒着遍历
            int start=0;
            int end=i-1;
            while(start<end){
                if(S[start]+S[end]>S[i]){
                    count+=end-start;
                    end--;
                }else{
                    start++;
                }
            }
            
        }
        return count;
    }
}

533.Two Sum-Closet to target: 点击打开链接

思路:还是 Two Sum双指针法,只是每次都要记录target与当前nums[start]+nums[end]的差值,并更新成最小的closet值,也就是最closet的。

 

public class Solution {
    /**
     * @param nums an integer array
     * @param target an integer
     * @return the difference between the sum and the target
     */
    public int twoSumClosest(int[] nums, int target) {
        if(nums==null || nums.length<0){
            return 0;
        }
        
        Arrays.sort(nums);
        
        int start=0,end=nums.length-1;
        int closet=Integer.MAX_VALUE;
        while(start<end){
            if(nums[start]+nums[end]==target){                           //如果nums[]+nums[]==target
                closet=0;                                                //此时就是最理想的情况,要return
                return closet;
            }else if(nums[start]+nums[end]<target){
                closet=Math.min(closet,target-nums[start]-nums[end]);
                start++;
            }else{
                closet=Math.min(closet,nums[start]+nums[end]-target);
                end--;
            }
        }
        return closet;
    }
}

 

public class Solution {
    /**
     * @param nums an integer array
     * @param target an integer
     * @return the difference between the sum and the target
     */
    public int twoSumClosest(int[] nums, int target) {                 //或者用和3Sum Closet通用方法
        if(nums==null || nums.length<0){
            return 0;
        }
        
        Arrays.sort(nums);
        
        int start=0,end=nums.length-1;
        int closet=Integer.MAX_VALUE;
        while(start<end){
            int diff=nums[start]+nums[end]-target;
            if(Math.abs(diff)<closet){
                closet=Math.abs(diff);
            }
            if(diff==0){
                closet=0;
                return closet;
            }else if(diff<0){
                start++;
            }else{
                end--;
            }
        }
        return closet;
    }
}

 

59.3Sum Closet:点击打开链接

 

public class Solution {
    /**
     * @param numbers: Give an array numbers of n integer
     * @param target : An integer
     * @return : return the sum of the three integers, the sum closest target.
     */
    public int threeSumClosest(int[] numbers, int target) {
        if(numbers==null || numbers.length<3){
            return 0;
        }
        
        Arrays.sort(numbers);
        
        int sum=0;
        int closet=Integer.MAX_VALUE;
        for(int i=0;i<numbers.length;i++){
            int start=i+1;
            int end=numbers.length-1;
            while(start<end){
                int diff=numbers[start]+numbers[end]+numbers[i]-target;  //先记录当前要用的三个数与target的差值
                if(Math.abs(diff)<closet){                               //每次都要比较当前绝对差值与closet的大小
                    closet=Math.abs(diff);                               //更新closet值
                    sum=numbers[start]+numbers[end]+numbers[i];          //并记录当前最小closet情况下的的sum
                }
                
                if(diff==0){                                             //差值为0就是最理想情况,此时要return closet
                    return sum;
                }else if(diff>0){
                    end--;
                }else{
                    start++;
                }
            }
        }
        return sum;
    }
}

58.4Sum:点击打开链接

思路:和3Sum想法一样,不同点在于循环遍历两个数,另外两个数一个是start,一个是end

注意:题目要求输出list里不能包括重复的小list,因此循环遍历的两个数分别要检查是不是和后面的数相等

 

public class Solution {
    /**
     * @param numbers : Give an array numbersbers of n integer
     * @param target : you need to find four elements that's sum of target
     * @return : Find all unique quadruplets in the array which gives the sum of
     *           zero.
     */
    public ArrayList<ArrayList<Integer>> fourSum(int[] numbers, int target) {
        ArrayList<ArrayList<Integer>> result=new ArrayList<>();
        if(numbers==null || numbers.length<4){
            return result;
        }
        Arrays.sort(numbers);
        
        for(int i=0;i<numbers.length-1;i++){                        
            if(i>0 && numbers[i]==numbers[i-1]){
                    continue;
            }
            for(int j=i+1;j<numbers.length;j++){
                if(j!=i+1 && numbers[j]==numbers[j-1]){
                    continue;
                }
                int start=j+1;
                int end=numbers.length-1;
                while(start<end){
                    int sum=numbers[i]+numbers[j]+numbers[start]+numbers[end];
                    if(sum>target){
                        end--;
                    }else if(sum<target){
                        start++;
                    }else{
                        ArrayList<Integer>  list=new ArrayList<>();
                        list.add(numbers[i]);
                        list.add(numbers[j]);
                        list.add(numbers[start]);
                        list.add(numbers[end]);
                        result.add(list);
                        start++;
                        end--;
                        while(start<end && numbers[start]==numbers[start-1]){
                            start++;
                        }
                        while(start<end && numbers[end]==numbers[end+1]){
                            end--;
                        }
                    }
                }
            }
        }
        return result;
    }
}

31. Partition Array:点击打开链接

例如:[3,2,2,1],k=2,Output:1

思路:“两大阵营”

          根据题意分阵营,左边都是小于k的数,右边都是大于k的数

          相向双指针遍历数组,如果左边遍历到的数小于k就left++,如果右边遍历到的数大于k就right--

          如果不属于我方阵营就和一个不属于对方阵营的数交换位置   

注意: 1.本题最后return the partitioning index,eg:the first index i nums[i] =k,因为每次left++可以保证return left的值就是题目所要求。

          2.题目还要求如果所以元素都比k小,就要返回数组的长度,例如:[1,1,1,1],k=2,Output:4

             这种情况就是一直left++,当left=3时,仍然满足while(left<=right && nums[left]<k),还会再left++一次,此时返回left=4            

 

public class Solution {
     /** 
     *@param nums: The integer array you should partition
     *@param k: As description
     *return: The index after partition
     */
    public int partitionArray(int[] nums, int k) {
	    if(nums==null || nums.length==0){
	        return 0;
	    }
	    
	    int left=0;
	    int right=nums.length-1;
	    while(left<=right){
	        while(left<=right && nums[left]<k){
	            left++;
	        }
	        while(left<=right && nums[right]>=k){
	            right--;
	        }
	        
	        if(left<=right){
	            int temp=nums[left];
	            nums[left]=nums[right];
	            nums[right]=temp;
	            left++;
	            right--;
	        }
	    }
	    return left;
    }
}

373.Partition Array by Odd and Even:点击打开链接

 

public class Solution {
    /**
     * @param nums: an array of integers
     * @return: nothing
     */
    public void partitionArray(int[] nums) {
        if(nums==null || nums.length==0){
            return;
        }
        
        int left=0;
        int right=nums.length-1;
        while(left<=right){                             //根据题意分两大阵营
            while(left<=right && nums[left]%2==1){      //奇数阵营
                left++;
            }
            while(left<=right && nums[right]%2==0){     //偶数阵营
                right--;
            }
            if(left<=right){
                int temp=nums[left];
                nums[left]=nums[right];
                nums[right]=temp;
                left++;
                right--;
            }
        }
    }
}

49. Sort Letters by Case:点击打开链接

 

public class Solution {
    /** 
     *@param chars: The letter array you should sort by Case
     *@return: void
     */
    public void sortLetters(char[] chars) {
       if(chars==null || chars.length==0){
           return;
       }
       
       int left=0;
       int right=chars.length-1;
       while(left<=right){                                         
           while(left<=right && chars[left]>='a' && chars[left]<='z'){       //小写字母阵营
               left++;
           }
           while(left<=right && chars[right]>='A' && chars[right]<='Z'){     //大写字母阵营
               right--;
           }
           
           if(left<=right){
               char temp=chars[left];
               chars[left]=chars[right];
               chars[right]=temp;
               left++;
               right--;
           }
       }
    }
}

144.Interleaving Positive and Negtive:点击打开链接

 

思路:与上面的两大阵营稍有不同,这题是用同向双指针,因为是正负数间隔,所以哪个符合条件哪个指针+2

         但是题目没有说明原数组正,负整数的个数,因此要先判断正负数的个数情况,哪个多哪个就作为index=0

 

class Solution {
    /**
     * @param A: An integer array.
     * @return: void
     */
    public void rerange(int[] A) {
        int posNum = 0, negNum = 0;  
         for (int i = 0; i < A.length; i++) {  
             if (A[i] > 0) {  
                 posNum++;  
             } else {  
                 negNum++;  
             }  
         }  
         int posIndex = 1, negIndex = 0;  
         if (posNum > negNum) {  
             posIndex = 0;  
             negIndex = 1;  
         }  
           
         while (negIndex < A.length && posIndex < A.length) {  
             while (negIndex < A.length && A[negIndex] < 0) {  
                 negIndex += 2;  
             }  
             while (posIndex < A.length && A[posIndex] > 0) {  
                 posIndex += 2;  
             }  
             if (posIndex < A.length && negIndex < A.length) {  
                 int tmp = A[posIndex];  
                 A[posIndex] = A[negIndex];  
                 A[negIndex] = tmp;  
                 posIndex += 2;  
                 negIndex += 2;  
             }  
         }  
     }  
}

148.Sort Colors:点击打开链接

3-way-partition问题

思路:1.由i遍历数组,leftPointer一直指向左边部分后一个数,rightPointer指向右边部分前一个数

         2.如果当前nums[i]属于左边部分,nums[leftPointer]和nums[i]交换位置,使得leftPointer真正指向一个属于左边部分的数

            然后leftPointer++,i++同步跟上

         3.如果当前nums[i]属于中间部分,i++表示跳过,因为中间部分的元素就要留在中间

         4.如果当前nums[i]属于右边部分,nums[rightPointer]和nums[i]交换位置,使得rightPointer真正指向一个属于右边部分的数

            然后rightPointer--,此时,i不能同步++向后移,因为不知道被换的nums[rightPointer]是不是也属于右边部分,

            所以还要从这个i位置开始看nums[i]属于哪个部分

注意:多跑几个例子就可以知道,i会比leftPointer走的快,所以即使交换后leftPointer指向的是左边阵营结束元素的下一个元素,也是i走过的元素,因此是1

           rightPointer指向的是右边阵营结束元素的下一个元素,但是方rightPointer的走向是向左的

 

class Solution {
    /**
     * @param nums: A list of integer which is 0, 1 or 2 
     * @return: nothing
     */
    public void sortColors(int[] nums) {
        if(nums==null || nums.length==0){
            return;
        }
        
        int leftPointer=0;                                     
        int rightPointer=nums.length-1;                        
        int i=0;                                               
        while(i<=rightPointer){                                
            if(nums[i]==0){
                swap(nums,i,leftPointer);                      //是0就被交换到1阵营
                leftPointer++;
                i++;
            }else if(nums[i]==1){                            
                i++;                                           //是1就跳过
            }else{
                swap(nums,i,rightPointer);                     //是2就被交换到当前2阵营
                rightPointer--;
            }
        }
    }
    
    private void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}

625.Partition Array II:点击打开链接

public class Solution {
    /**
     * @param nums an integer array
     * @param low an integer
     * @param high an integer
     * @return nothing
     */
    public void partition2(int[] nums, int low, int high) {
        if(nums==null || nums.length==0){
            return;
        }
        
        int i=0;
        int leftPointer=0;
        int rightPointer=nums.length-1;
        while(i<=rightPointer){
            if(nums[i]<low){
                swap(nums,i,leftPointer);
                leftPointer++;
                i++;
            }else if(nums[i]>=low && nums[i]<=high){
                i++;
            }else if(nums[i]>high){
                swap(nums,i,rightPointer);
                rightPointer--;
            }
        }
    }
    
    private void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}

143.Sort Colors II:点击打开链接

彩虹排序问题 : O(nlogk)

思路:先分成两分,再递归分

例如:[3,2,2,1,4],k=4

         先分成colorMid=(colorFrom+colorTo)/2=(1+4/)2=2,所以开始的两分是[2,2,1,3,4],再递归分每一分[2,2,1]和[3,4]

         也就是两分先有个大致顺序,再不断递归局部的顺序,直到整体完全有序。

注意:前面两个return;

class Solution {
    /**
     * @param colors: A list of integer
     * @param k: An integer
     * @return: nothing
     */
    public void sortColors2(int[] colors, int k) {
        if(colors==null || colors.length<k-1){
            return;
        }
        rainbowSort(colors,1,k,0,colors.length-1);
    }
    
    private void rainbowSort(int[] nums,int colorFrom,int colorTo,int left,int right){
        if(colorFrom==colorTo){
            return;
        }
        if(left>right){
            return;
        }
        
        int colorMid=(colorFrom+colorTo)/2;
        int l=left,r=right;
        while(l<=r){
            while(l<=r && nums[l]<=colorMid){
                l++;
            }
             while(l<=r && nums[r]>colorMid){
                r--;
            }
            if(l<=r){
                int temp=nums[l];
                nums[l]=nums[r];
                nums[r]=temp;
                l++;
                r--;
            }
        }
        
        rainbowSort(nums,colorFrom,colorMid,left,r);                   //while(l<=r)是循环条件,所以跳出了l>r是跳出条件
        rainbowSort(nums,colorMid+1,colorTo,l,right);                  //所以下一次递归的时候一定是l>r,r在前面
    }
}

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值