The Array |

HoHo 完成了Tree之章后,决定下一个章节选Array。 Array一直是我的一个软肋,和List的题目一个问题,我经常被index问题搞的头晕脑胀! 希望做这一遍 LeetCode上的66 题能让自己有所提升。与Tree之章不同,我不再会记录所有66道题目,我将只记难想或难做对的题目。


Product of Array Except Self : *

Tricky one. scan twice from left and right respectively. Record all right side product in first ite, record all left side product in second ite. To use constant space, scan from left to right and build solution at the same time.

"
因此执行两趟循环:
第一趟正向遍历数组,计算x0 ~ xi-1的乘积
第二趟反向遍历数组,计算xi+1 ~ xn-1的乘积
" --书影
public class Solution {
    public int[] productExceptSelf(int[] nums) {
        int[] res = new int[nums.length];
        int temp = 1;
        res[nums.length-1] = 1;
        for(int i=nums.length-2;i>=0;i--){
            temp *= nums[i+1];
            res[i] = temp;
        }
        temp = 1;
        for(int i=1; i<=nums.length-1; i++){
            temp *= nums[i-1];
            res[i] *= temp;
        }
        return res;
    }
}

Find Minimum in Rotated Sorted Array : ***

Tricky one. Cost me a while though it's my second time doing this. Notice, this process uses binary search, but  differ from normal binary search. The point is, if we search for 8 in 1~10 use binary search then we can finally end at 8 only because we know we are looking for 8. But now we are looking for min, we don't know what it is unless we go through all possible candidates. The key point is maintaining min value while binary search.  For example [5,6,7, 1 , 2,3,4 ], we find 1 at first split, but we never know it is the min. And to proceed binary search we MUST either set s = mid -1 or set e = mid + 1, otherwise it is not exhaustive and  will not terminate. To understand binary search, keep in mind, the mid-point will always be excluded in next search. 

As a followup, what if containing duplicates. It only asks for a slight modification to keep the same time complexity, but it is really difficult to realize it sometime. Remember this one.

public class Solution {
    public int findMin(int[] nums) {
        int s = 0;
        int e = nums.length - 1 ;
        int min = Integer.MAX_VALUE;
        while(s<=e){
            int mid = (s+e)/2;
            min = Math.min(min,nums[mid]);
            if(nums[mid] > nums[e])
                s = mid + 1;
            else
                e = mid - 1;
        }
        return min;
    }
}

Follow up for "Find Minimum in Rotated Sorted Array": What if duplicates are allowed? Would this affect the run-time complexity? How and why?

public class Solution {
    public int findMin(int[] nums) {
        int min = Integer.MAX_VALUE;
        int s = 0;
        int e = nums.length-1;
        while(s<=e){
            int mid = (s+e)/2;
            min = Math.min(nums[mid],min);
            if( nums[mid] > nums[e]){
                s = mid + 1;
            }else if(nums[mid] < nums[e]){
                e = mid - 1;
            }else{
                e --;
            }
        }
        return min;
    }
}

To fully understand the spirit of this scenario.
"
在每次迭代中,分三种情况:
(1)如果target==A[m],那么m就是我们要的结果,直接返回;
(2)如果A[m]<A[r],那么说明从m到r一定是有序的(没有受到rotate的影响),那么我们只需要判断target是不是在m到r之间,如果是则把左边缘移到m+1,否则就target在另一半,即把右边缘移到m-1。
(3)如果A[m]>=A[r],那么说明从l到m一定是有序的,同样只需要判断target是否在这个范围内,相应的移动边缘即可。

根据以上方法,每次我们都可以切掉一半的数据,所以算法的时间复杂度是O(logn),空间复杂度是O(1)。代码如下:

"---Coder_Ganker (大神就是大神,Code写的明白,注释也是明白)
public class Solution {
    public int search(int[] nums, int target) {
        if(nums == null || nums.length == 0)
            return -1;
        int e = nums.length-1;
        int s = 0;
        while(e >= s){
            int mid = (s+e)/2;
            if(nums[mid] == target)
                return mid;
            if(nums[mid] < nums[e]){
                if(nums[mid] < target && target <= nums[e])
                    s = mid + 1;
                else
                    e = mid - 1;
            }else{
               if( nums[s]<= target && target < nums[mid])
                   e = mid - 1;
               else
                   s = mid + 1;
            }
        }
        return -1;
    }
}

Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?

public class Solution {
    public boolean search(int[] nums, int target) {
         if(nums == null || nums.length == 0)
            return false;
        int e = nums.length-1;
        int s = 0;
        while(e >= s){
            int mid = (s+e)/2;
            if(nums[mid] == target)
                return true;
            if(nums[mid] < nums[e]){
                if(nums[mid] < target && target <= nums[e])
                    s = mid + 1;
                else
                    e = mid - 1;
            }else if(nums[mid] > nums[e]){
               if( nums[s]<= target && target < nums[mid])
                   e = mid - 1;
               else
                   s = mid + 1;
            }else{
                e--;
            }
        }
        return false;
    }
}

Find Peak Element : *

Learn binary search this one. Beyond binary search prototype, BS could be very flexible to work on different requirements. Be aware of what we are looking for, and how to track it or locate it. 

public class Solution {
    public int findPeakElement(int[] nums) {
        int l = 0;
        int r = nums.length - 1;
        while(l < r){
            int mid = (l+r)/2;
            if(nums[mid] > nums[mid + 1]){
                r = mid;
            }else{
                l = mid + 1;
            }
        }
        return l;
    }
}


Sort Colors  : **

Tricky one. For some problems, the thoughts may be easy, but it asks for very specific implementation. Like this one, it is easy to realize we should keep red all to left and keep blue all to right, but another key point of solving this problem is to find out that while iterating we have " i<=blue_index " and we add to red_index, we don't need to "i--" as we do when add to blue_index.

public class Solution {
    public void sortColors(int[] nums) {
        if(nums == null || nums.length < 1)
            return;
        int red_index = 0;
        int blue_index = nums.length - 1;
        for(int i=0;i<=blue_index;i++){
            if(nums[i] == 0){
                nums[i] = nums[red_index];
                nums[red_index] = 0;
                red_index ++;
            }else if(nums[i] == 2){
                nums[i] = nums[blue_index];
                nums[blue_index] = 2;
                blue_index --;
                i--;
            }
        }
    }
}


Spiral Matrix II : *

This one is not difficult, but hard to be right. The thought is clear, spirally build up the matrix.A take away from this problem is that never hard code anything. For example here, the building up process is regulated by current lvl, at first ite, it appears that every start at 0, but we should write start at l (though l = 0 at first ite), because later in following ites, l is updating, starting point is updating, not 0 anymore!

public class Solution {
    public int[][] generateMatrix(int n) {
    if(n < 0)
        return null;
    int[][] res = new int[n][n];
    int lvl = n/2;
    int num = 0;
    for(int l =0 ; l < lvl; l++){
        for(int i = l; i
  
   l;i--){
            res[n-l-1][i] = ++num;
        }
        for(int i=n-l-1;i>l;i--){
            res[i][l] = ++num;
        } 
    }
    if(n%2 == 1)
        res[lvl][lvl] = n*n;
    return res;
    }   
}
  

Search a 2D Matrix : *** 

This one takes me a long while. BS is definitely my weakness. Worth summarizing this typical BS problem. I have pointed the prototype of BS previously. Should always keep that in mind, and don't attempt to modify.  The thing I want to emphasize here is that when  " r == l " condition meets, after one more iteration, the process will end. And where would it end? In the last iteration, it could be either  r = r - 1  or  l = l + 1 . We may use BS for different purposes. If we simply want to decide whether array contains something, then we don't care how " r or l " end. The problem is that there are more times we are not checking existence, we are relying on end condition. We are trying to locate someplace depending on r or l .  This is not hard to decide, just remember the condition of changing r and l, then see in specific case how it ends.  

Specifically for this problem, the first BS takes me while to understand, I thought " l = mid " instead of " l = mid + 1" because we can't exclude mid-th row, it is very likely the one we want. But actually even we exclude it at first time, we end up choosing it after all. To understand this, need to look into specific cases when "r=l". I know I should not talk so much bullshit, for now, keep the fcking BS rule in mind. 

    public boolean searchMatrix(int[][] matrix, int target) {
    if(matrix == null || matrix.length==0 || matrix[0].length==0)
        return false;
    int l = 0;
    int r = matrix.length-1;
    while(l<=r)
    {
        int mid = (l+r)/2;
        if(matrix[mid][0] == target) return true;
        if(matrix[mid][0] > target)
        {
            r = mid-1;
        }
        else
        {
            l = mid+1;
        }
    }
    int row = r;
    if(row<0)
        return false;
    l = 0;
    r = matrix[0].length-1;
    while(l<=r)
    {
        int mid = (l+r)/2;
        if(matrix[row][mid] == target) return true;
        if(matrix[row][mid] > target)
        {
            r = mid-1;
        }
        else
        {
            l = mid+1;
        }
    }   
    return false;
}

大神就是大神。 这题既然是经典,记住好了。 我这脑子也不会是创造性选手了
public class Solution {
    public void setZeroes(int[][] matrix) {
        if(matrix == null || matrix[0] == null)
            return ;
        boolean col_flag = false;
        boolean row_flag = false;
        for(int i=0; i < matrix.length; i++){
            if(matrix[i][0] == 0){
                col_flag = true;
                break;
            }
        }
        for(int i=0; i < matrix[0].length; i++){
            if(matrix[0][i] == 0){
                row_flag = true;
                break;
            }
        }
        for(int i=1;i
   


This problem is not hard, the reason to post them here is to standardize the way of skipping indexes when condition met. There are multiple ways of doing this, and for the follow up question, I was trying using  a while loop, and argument index when duplicate. It turns out that is not a easy way to go. The right way of doing this is, skip duplicate automatically, modify manually which means check for modification, not for skipping.
//I
public class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums == null || nums.length == 0)
            return 0;
        int cur = 0;
        for(int i=0;i
   

Longest Consecutive Sequence :  Your algorithm should run in O(n) complexity.  需要排序的问题要求O(n) 就是空间换时间。
Classic problem. Familiar yourself with Arraylist method.(HashSet, HashMap, HashTable, LinkedList... Java is fcking stupid for making a mess of those classes unnecessarily. 
But bear with it for now.) Remember this one. 
public class Solution {
    public List
   
    
     > generate(int numRows) {        
        List
     
      
       > res = new ArrayList
       
        
         >(); if(numRows == 0) return res; List
         
           prev = new ArrayList
          
           (); prev.add(1); res.add(prev); for(int r = 2;r<=numRows;r++){ List
           
             cur = new ArrayList
            
             (); cur.add(1); for(int i=2; i < r ;i++){ cur.add(prev.get(i-2) + prev.get(i-1)); } cur.add(1); res.add(cur); prev = cur; } return res; } } // follow up //Given an index k, return the kth row of the Pascal's triangle. //For example, given k = 3, //Return [1,3,3,1]. public class Solution { public List
             
               getRow(int rowIndex) { rowIndex += 1;//Use as No. of row for consistency here ArrayList
              
                res = new ArrayList
               
                (); if(rowIndex < 1) return res; res.add(1); for(int r=2; r<=rowIndex; r++){ for(int j = res.size()-1; j >0; j--){ res.set(j, res.get(j) + res.get(j-1)); } res.add(1); } return res; } }
               
              
             
            
           
          
         
        
       
      
     
    
   



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值