The Array ||

Merge Sorted Array.

这个题实现并不难,关键是要从后往前扫,才能保证从后往前存入的时候不会把没有扫到的值覆盖掉。

Subsets  这道题本来没啥好说的,recursion想法和 Combination 题目近似,但是在做的时候偶然发现一个问题:在IntelJ里面追踪res的时候,尽管最后结果对,但过程中res变化不正常,

以nums = [1,2]为例, 如果每次加入res时候不传temp对copy而是传本身,在每次迭代中输出res,结果如下:

[[]]
[[1], [1]]
[[1], [1, 2], [1, 2]]
[[2], [1], [1, 2], [2]]
[[], [1], [1, 2], [2]]

可以看出,最后是对的,但过程但记录是不合理但。如何换位传入 remp对copy,整个过程就合理了

[[]]
[[], [1]]
[[], [1], [1, 2]]
[[], [1], [1, 2], [2]]

最后发现是temp在加入res时候没有copy,尽管在同一层最好的变化是被抵消了吧,但是还是不规范,一定要注意recursion中传参问题。另外附加一种iteration的经典思路,code来自Coder_Ganker大神

public class Solution {
    public List
   
   
    
    
     
     > subsets(int[] nums){
         List
     
     
      
      
       
       > res = new ArrayList
       
        
        
          >(); List 
         
           temp = new ArrayList 
          
            (); if(nums == null || nums.length == 0) return res; Arrays.sort(nums); helper(nums,0,res,temp); return res; } public void helper(int[] nums, int s, List 
            
            
              > res, List 
             
               temp ){ res.add(new ArrayList 
              
                (temp)); if(s>nums.length-1) return; for(int i=s;i 
               
                 (temp)); temp.remove(temp.size()-1); } } } //Iteration public ArrayList 
                 
                 
                   > subsets(int[] S) { ArrayList 
                   
                   
                     > res = new ArrayList 
                     
                     
                       >(); res.add(new ArrayList 
                      
                        ()); if(S == null || S.length == 0) return res; Arrays.sort(S); for(int i=0;i 
                       
                         item = new ArrayList 
                        
                          (res.get(j)); item.add(S[i]); res.add(item); } } return res; } 
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   

这个题思路很好想,但是做了很多遍才做对! 面试中一道题出错三次基本就完了,这道题我错了四五回。。。同样的思路不同的实现角度的复杂度差别很大。我当时做的是in-place的,我用的方法要考虑的edge case不少,很容易出错。下面做法是Coder_Ganker 大神的, 用 O(m)space, 虽然是二维dp的题目,用一维数组来解决大大简化了代码。

public class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        if(obstacleGrid == null || obstacleGrid.length==0 || obstacleGrid[0].length==0)  
            return 0; 
        int[] res = new int[obstacleGrid[0].length];
        res[0] = 1;
        for(int i=0; i
    
    
     
     0)
                    res[j] += res[j-1];
            }
        }
        return res[obstacleGrid[0].length-1];
    }
}
    
    

Search for a Range  : ....

Binary search has always been my weakness. However, consider I just seriously start doing algorithm coding problems, bear with it for now. I should take a big lesson from this one. What is A binary search do? --- it always go to left OR right part in next iteration until two sides finally merge.  Where does binary search end? --- In last iteration, when l == r, you can either change r or change l, which is both correct or harmless. The question is, I should know clearly which one is finally changing and which one remains in right ending position.  In this problem, we do 2 BSs to find right position and left respectively. We want to use ll as l and rr as r, so we modify lr and rl at end of two BSs.

public class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[2];
        if(nums == null || nums.length == 0)
            return res;
        int ll = 0;
        int lr = nums.length - 1;
        while(ll <= lr){
            int mid = (ll+lr)/2;
            
            if(nums[mid] >= target){
                lr = mid - 1;
            }else{
                ll = mid + 1;
            }
        }
        int rl = 0;
        int rr = nums.length - 1;
        while(rl <= rr){
            int mid = (rl+rr)/2;
            
            if(nums[mid] > target){
                rr = mid - 1;
            }else{
                rl = mid + 1;
            }            
        }
        if(ll <= rr)
            res = new int[]{ll,rr};
        else
            res = new int[]{-1,-1};
        return res;
    }
}


Jump Game : *

Jump Game II : **

Follow up is returning minimum steps needed to reach the last index.  The code is also O(n) solution. 

Coder_Ganker .... 大神就是大神 。。。记住for循环这种用法

 另外还加了一种实现,同样的思路,用的是for + while, 注意for 的用法, 实质是 while + while 

public class Solution {
    public boolean canJump(int[] nums) {
        if(nums == null || nums.length == 0)
            return false;
        int reach = 0;
        for(int i = 0; i<=reach && i< nums.length; i++){
            reach = Math.max(nums[i]+i,reach);
        }
        if(reach >= nums.length - 1)
            return true;
        return false;
    }
}

public class Solution {
    public int jump(int[] nums) {
        if(nums == null || nums.length == 0)
            return 0;
        int reach = 0;
        int last_reach = 0;
        int step = 0;
        for(int i=0; i<=reach && i
   
   
    
    last_reach){
                last_reach = reach;
                step += 1;
            }
            reach = Math.max(nums[i]+i, reach);
        }
        if(reach >= nums.length-1){
            return step;
        }else{
            return 0;
        }
    }
}

//Another implement, same idea.

public class Solution {
    public int jump(int[] nums) {
        int reach=0,last_reach=0,num=0;
        int n  = nums.length;
        for(int i=0;i
    
    
     
     =n-1)break;  
            while(i<=last_reach)  
            {  
                reach=Math.max(reach,i+nums[i]);  
                ++i;  
            }  
            num++;  
            last_reach=reach;   
            if(last_reach < i){
                return 0;
            }
        }  
        return num;  
    }
}
    
    
   
   

3Sum Closest    : ***
哎 这个题比较绕啊,到了26左右AC的题目,越来越容易出错了。看了思路都不一定很快能做对。这个题说到家还是Binary Search啊。觉得差不多到火候了,Array对题目做到现在四十道左右了,很多Binary Search对题目都不容易一次做对! 这个题目关键是在BS中维护量, 维护最小差, 这个差本身可正可负,但是在update的时候,比较的是绝对值。这里有点绕, 这跟之前一个题目BS找最小值一个模式,这种不确定搜索,是需要遍历+维护。注意BS结束的点,并不代表最小值或要找的点。

public class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int diff = target - nums[0]- nums[1] - nums[2];
        if(nums.length == 3){
            return target - diff;
        }
        for(int i=0; i< nums.length-2;i++){
            int t2 = target - nums[i];
            int d2 = helper(nums,t2,i+1,nums.length-1);
            diff = Math.abs(diff) > Math.abs(target - nums[i] - (t2 - d2) )? target - nums[i] - (t2 - d2):diff;
        }
        return target - diff;
    }
    
    public int helper(int[] nums, int target, int s, int e){
        int diff = target - nums[s] - nums[s+1];
        if(s+1 == e)
            return diff;
        while(s < e){
             diff = Math.abs(diff) > Math.abs(target - nums[s] - nums[e] )? target - nums[s] - nums[e] : diff;
            if(nums[s] + nums[e] == target){
                diff = 0;
                break;
            }else if(nums[s] + nums[e] > target){
                e -- ;
                
            }else{
                 s++;
            }
        }
        return diff;
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值