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;
}
}
(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;
}
}
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
//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
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; } }