Sunday, September 29, 2013

74. Search a 2D Matrix ------ M

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

Example 1:

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
Output: true

Example 2:

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
Output: false
A:
----------------------3rd pass---------------------------------
This is a typical problem of binary search.
You may try to solve this problem by finding the row first and then the column. There is no need to do that. Because of the matrix's special features, the matrix can be considered as a sorted array. Your goal is to find one element in this sorted array by using binary search.


class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size();
        if(m==0)
            return false;
        int n = matrix[0].size();        
        int start = 0, end = m*n-1;// treat it as 1 D array
        while(start<=end){
            int mid = start+(end-start)/2;
            if(matrix[mid/n][mid%n] == target)
                return true;
            else if(matrix[mid/n][mid%n] > target){
                end = mid-1;
            }else{
                start = mid+1;
            }
        }
        return false;
    }
};
Mistakes:
1:    low <= high 给写成 low < high
2: 一开始没有用mid,而直接在下面写的,就TMD给忘了 / 2



-------------------------------2nd pass ---------search for row first, then search for col----------------
public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length, n = matrix[0].length;
        int low = 0, high = m-1;
        while(low<high){
            if(low == high - 1){
                if(matrix[high][0] <=target)
                    low = high;
                break;
            }
            int mid = (low+high)/2;
            if(matrix[mid][0] > target){
                high = mid-1;
            }else{
                low = mid;
            }
        }
        int left = 0, right = n-1;
        while(left<right){ // search the row, indexed by low
            int mid = (left+right)/2;
            if(matrix[low][mid]==target)
                return true;
            if( matrix[low][mid] < target)
                left = mid+1;
            else
                right = mid-1;
        }
        return matrix[low][left]==target;
    }
}

Mistakes:

最后 确定了low和left后,忘了检测该位置是否为target了


--------------------------1st pass-----------------------
最简单的, 就是搜索第一列,找到行, 再搜索该行。
public class Search2DMatrix {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length, n = matrix[0].length, i =0;
        while(i+1<Math.min(m,n) && matrix[i][i]<target && matrix[i+1][i+1]<target)
            i++;
        int col = i,row = i;
        if( matrix[row][n-1] >= target ){ // if the last on row i < target, search this row
            while(col+1<n && matrix[row][col+1] <= target)
                col++;
        }else{ // else, linearly search the i_th row
            while(row+1<m && matrix[row+1][col] <= target)
                row++;
        }
        return matrix[row][col]==target;
    }
}

但是上面这个解法是错误的,  自己举个例子想想是为啥??????

Mistakes:
1: int  mid = (low + high) / 2 时, 当low =0., high =1 ----> mid =0  导致死循环
   解决方法,就是在while中加一个if 语句,来检测之。

2:当只有1行的时候, 就没有运行那个check  column的while语句了。


Learned:

Saturday, September 28, 2013

Minimum Window Substring !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Q:
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S = "ADOBECODEBANC"
T = "ABC"

Minimum window is "BANC".
Note:
If there is no such window in S that covers all characters in T, return the emtpy string "".
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

A:
之前根据max-crossing subArray的想法,貌似在计算的cross时候,还是不够efficiency.
是不是,可以根据KMP算法呢???


双指针,动态维护一个区间。尾指针不断往后扫,当扫到有一个窗口包含了所有T的字符后,然后再收缩头指针,直到不能再收缩为止。最后记录所有可能的情况中窗口最小的
------------复杂度呢???? 由于被查找的string最多也就265个字符。因此,可以把其看做是constant的, 那么,复杂度就是O(n)了 -------------------


这道题目,最大的注意之处,就是head 和tail指针的 update 方式。不能处理得太粗糙。



Mistakes:
1: 在find cross 的时候,由于low high是inclusive的,因此在计算长度的时候, 要high-low +1
            for (int i = leftStart; i <= rightEnd+1 - curLen; i++) {
2: 题意理解错误。
Input: "a", "aa"
Output: "a"
Expected: ""
从这里来看, 允许重复的字母的。 也必须出现最少相同的次数。

3: 认为最后tail会== S.length() 是正确的, 但是,之间,还依然是inclusive的。  所以,不需要把它当做 exclusive来对待。

4: 哎,犯了一个很SB的错误。 在update  tail 指针的时候,要对每个位置,检查加上后,是否满足match条件,如果是,则退出来。
但是,原本,就随手写了个while (!allFind(count, times) && tail < S.length()) {   这样,逻辑是比较混乱的。


Learned:


-------------第二遍-----------, T中是有计数的,例如S= "a", T = "aa" ,结果应该是false------
 另外,这次,当S超过10000的时候,会有说String index out of 10000的错误。不知道为什么??????????????????????????????????
????????????????
public class Solution {
    public String minWindow(String S, String T) {
        if(S==null || T == null)
            return "";
        HashMap<Character, Integer> origMap = new HashMap<Character, Integer>();
        HashMap<Character, Integer> findMap = new HashMap<Character, Integer>();
        HashMap<Character, Integer> totalMap = new HashMap<Character, Integer>();
        int start = 0,  minStart = S.length(),minEnd = Integer.MAX_VALUE;
        for(int i = 0;i<T.length();i++ ){
            char ch = T.charAt(i);
            if(origMap.containsKey(ch)){
                origMap.put(ch,origMap.get(ch)+1);
            }else{
                origMap.put(ch,1);
            }
        }
        // if a char in S are find in T, if enough apperarance of char, we put it in findMap, otherwise put in totalMap
        for(int i =0;i<S.length();i++){
            char ch = S.charAt(i);
            if(origMap.containsKey(ch) == false)
                continue;
            int count = origMap.get(ch);
            if(findMap.containsKey(ch)){
                findMap.put(ch,findMap.get(ch)+1);
            }else{
                if(totalMap.containsKey(ch)){
                    totalMap.put(ch,totalMap.get(ch)+1);
                }else{
                    totalMap.put(ch,1);
                }
                // check if enough appearance
                if(totalMap.get(ch)>=origMap.get(ch)){
                    findMap.put(ch,totalMap.get(ch));
                    totalMap.remove(ch);
                }
            }
            // check whether we can shrink
            while(findMap.size()==origMap.size()){// find a match, and begin to shrink
                char newChar = S.charAt(start);
                if(origMap.containsKey(newChar)){
                    if(findMap.get(newChar) == origMap.get(newChar)){ // begin to delete
                        totalMap.put(newChar,findMap.get(newChar)-1);
                        if(minEnd - minStart > i - start){
                            minStart = start;
                            minEnd = i;
                        }
                        findMap.remove(newChar);
                    }else{
                        findMap.put(newChar,findMap.get(newChar)-1);
                    }
                }
                start++;
            }
        }
        return minStart==S.length()?"":S.substring(minStart,minEnd+1);
    }
}




---------------3 rd Pass -------------不错不错, 方法虽然是新的idea,但是, 只改了几个拼写错误 , 然后,就一遍过了 --------  哎,Tiger,有进步阿-------------------

IDEA:
用一个HashSet记录是不T 中出现过的字母。 (其实可以用查询MapT,usedMap来代替的,为了清晰,我们这里还是用了)
然后,用一个HashMap, 记录出现字母在T中的次数。 以及发现了的次数。
然后,如果全部发现的话,就把这个对象放进另一个HashMap中缓存起来(当然,如果再次发现的话,也要在这个缓存的Map中更新 nFind。

public class Solution {
    public String minWindow(String S, String T) {
        String result = null;
        // IDEA: use to map to count the strings , if for a char, all are used,
        // Note that duplicates in T are also counted
        // build HashMap for T
        HashMap<Character, Node> mapT = new HashMap<Character, Node>();
        HashSet<Character> set = new HashSet<Character>();
        HashMap<Character, Node> usedMap = new HashMap<Character, Node>();
        for (int i = 0; i < T.length(); i++) {
            char ch = T.charAt(i);
            if (mapT.get(ch) == null) {
                Node tmp = new Node();
                mapT.put(ch, tmp);
                set.add(ch);
            } else {
                mapT.get(ch).count++;
            }
        }
        int begin = 0;// begin of current sub window
        for (int i = 0; i < S.length(); i++) {
            char ch = S.charAt(i);
            if (!set.contains(ch)) { // not in the T String
                continue;
            }

            Node tmp = mapT.get(ch);
            if (tmp == null) {// should be in usedMap,
                tmp = usedMap.get(ch);
                tmp.nFind++;
            } else {// ch appeared in mapT, then we need check
                tmp.nFind++;
                if (tmp.count == tmp.nFind) { // all appearance have been found
                    mapT.remove(ch);
                    usedMap.put(ch, tmp);
                }
            }
            // check whether we should shrink, and from beginning
            while (mapT.isEmpty()) {
                if (result == null || result.length() > i - begin + 1) {
                    result = S.substring(begin, i + 1);
                }
                char tmpChar = S.charAt(begin);
                begin++;
                if (set.contains(tmpChar)) {
                    Node tmpNode = usedMap.get(tmpChar);
                    if (tmpNode.nFind == tmpNode.count) {
                        usedMap.remove(tmpChar);
                        mapT.put(tmpChar, tmpNode);
                    }
                    tmpNode.nFind--;
                }
            }
        }
        return result == null ? "" : result;
    }
}

class Node {
    public int count, nFind;// count if char, and number of find char

    public Node() {
        count = 1;
        nFind = 0;
    }
}








75. Sort Colors ---- M !!

Given an array nums with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.

We will use the integers 01, and 2 to represent the color red, white, and blue, respectively.

You must solve this problem without using the library's sort function.

 

Example 1:

Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

Example 2:

Input: nums = [2,0,1]
Output: [0,1,2]

 

Constraints:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] is either 01, or 2.

 

Follow up: Could you come up with a one-pass algorithm using only constant extra space?

A:

----------------下面这个解法,有两个错误的,自己看看,错在哪里?------

public class Solution {
    public void sortColors(int[] A) {
        int pre0 = -1,after2 = A.length;// i is pre
        for(int i = 0;i<A.length;i++){
            if(A[i] ==0){
                pre0++;
                swap(A,pre0,i);
            }else if(A[i] == 2){
                after2--;
                swap(A,i,after2);
                i--;
            }
        }
    }
    private void swap(int [] A, int i,int j){
        A[i] ^= A[j];
        A[j] ^= A[i];
        A[i] ^= A[j];
    }
}










Mistakes:

1: swap这个算法,是不对的。  问题就出自,i,j在flag sort里,有可能是相等的。
2: i<A.length 是不对的, 会导致下标越界

------------------4th pass-----------------
public class Solution {
    public void sortColors(int[] A) {
        int pre0 = -1,after2 = A.length;// i is pre
        for(int i = 0;i<after2;i++){
            if(A[i] ==0){
                pre0++;
                swap(A,pre0,i);
            }else if(A[i] == 2){
                after2--;
                swap(A,i,after2);
                i--;
            }
        }
    }
    private void swap(int [] A, int i,int j){
        int tmp = A[i];
        A[i] = A[j];
        A[j] = tmp;
    }
}



---------下面是用one pass 来做的------利用到了2个pointer------
当runner遇到2 的时候, 和后面交换了之后, 要记得把该runner退一步,重新这个从后面刚switch过来的值。 -------而遇到0 的时候,不用退后。


class Solution {
public:
void sortColors(vector<int>& nums) {
// i for place 0 lasted filled, and j for lastly fill 2(backward)
int i = -1, j = nums.size();
for (int k = 0; k < j; k++) {
if (nums[k] == 0) {
swap(nums[++i], nums[k]);
if (k != i) {
k--;
}
} else if (nums[k] == 2) {
swap(nums[--j], nums[k]);
if (k != j) {
k--;
}
}
}
}
};

Friday, September 27, 2013

77 Combinations

Q:
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
For example,
If n = 4 and k = 2, a solution is:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
A:
#####递归#############
class Solution:
    def combine(self, n: int, k: int):
        return self.helper(1,n,k)
    
    def helper(self, a: int, b: int, len: int):
        if  b - a + 1 < len or len <= 0:
            return []
        if len == 1:
            return [[i] for i in range(a,b+1)]
        res = []
        for i in range(a,b+1):
            nextList = self.helper(i+1,b, len - 1)
            for tmp in nextList:
                tmp.insert(0, i)
            res.extend(nextList)
        return res

#####循环#############

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        res = []
        for kk in range(1,k+1):
            if kk ==1:
                res = [ [t] for t in range(1,n+1)]
            else:
                newRes = []
                for tmp in res:
                    for lastVal in range(tmp[-1]+1, n+1):
                        newTmp = tmp.copy()
                        newTmp.append(lastVal)
                        newRes.append(newTmp)
                res = newRes
        return res


------4th pass----------是每次分两种情况,
1):   取了第一个数字,
2):   不取第一个数字---------------

public class Solution {
    public List<List<Integer>> combine(int n, int k) {
        return helper(1,n,k);
    }
    private List<List<Integer>> helper(int start,int end,int k){
        List<List<Integer>> ll  = new LinkedList();
        if(k<=0 || k>(end-start+1))
            return ll;
        if(k==1){
            for(int i = start;i<=end;i++){
                List<Integer> l = new LinkedList();
                l.add(i);
                ll.add(l);
            }
            return ll;
        }
        for(List<Integer> tmp : helper(start+1,end,k-1)){
            tmp.add(0,start);
            ll.add(tmp);
        }
        ll.addAll(helper(start+1,end,k));
        return ll;
    }
}




Mistakes:
这道题目的,可能犯得错误,就在于k和start,end的比较。



Learned:
1:    当 all的类型是ArrayList<ArrayList<Integer>>的时候,下面的语句
                all.add(new ArrayList<Integer>(i));
所加入的都是空的ArrayList. 不知道为什么???? 因此要一个个地加。 
一个constructor,当是int 参数时,是给定的initial capacity.
public class Solution {
public ArrayList<ArrayList<Integer>> combine(int n, int k) {
    return combine(1, n, k);
}
public ArrayList<ArrayList<Integer>> combine(int start, int end, int k) {
    ArrayList<ArrayList<Integer>> all = new  ArrayList<ArrayList<Integer>>();
    if(end - start +1 < k  )
        return all;
    // each time, we shrink the size of k
    
    
   if( k == 1){ // 
         for(int i =start; i <= end;i++){
            ArrayList<Integer> al = new  ArrayList<Integer>();
            al.add(i);
            all.add(al);
         }
         return all;
    }else{
         all = combine(start+1,end,k-1);
         for(ArrayList<Integer> al: all) // all with start, 
            al.add(0,start);
        // all without start
         ArrayList<ArrayList<Integer>> newAll = combine(start+1,end,k);
         all.addAll(newAll);
         return all;
    }
}

}

----------------3rd Pass--------------------思路想的一样,但是, 犯了个错误, 就是 在for 循环里, 每次combine了一个 -------------靠,没有犯错,是不自信,在Eclipse中先运行拉下,结果打印的时候, 参数成了那个all了。 白调试了20分钟。

public class Solution {
    public List<List<Integer>> combine(int n, int k) {
        return helper(1,n,k);
    }
    private List<List<Integer>> helper(int start, int end, int k ){
        List<List<Integer>> all = new LinkedList<List<Integer>>();
        if(k==1){
            for(int i=start;i<=end;i++){
                List<Integer> list = new LinkedList<Integer>();
                list.add(i);
                all.add(list);
            }
        }else{
            for(int i =start;i<=end-k+1;i++){
                List<List<Integer>> oneLess = helper(i+1,end,k-1);
                for(List<Integer> al : oneLess)
                    al.add(0,i);
                all.addAll(oneLess);
            }
        }
        return all;
    }
}





84. Largest Rectangle in Histogra (hard) !!!!!!!!!!!!!!!!

Given an array of integers heights representing the histogram's bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.

 

Example 1:

Input: heights = [2,1,5,6,2,3]
Output: 10
Explanation: The above is a histogram where width of each bar is 1.
The largest rectangle is shown in the red area, which has an area = 10 units.

Example 2:

Input: heights = [2,4]
Output: 4

 

Constraints:

  • 1 <= heights.length <= 105
  • 0 <= heights[i] <= 104

A:
--------------4 rd -------------------依然是用2个stack--------------------
 代码看2nd实现。
犯的错误:
1:当要pop出indexstack之后, 要push进去的,不是当前的i,而是当前最远到达的index(因为之后的,都至少是这个height[i]的高度。
2:  while的时候,没有先检查是否是stack.isEmpty()





 ------------------------1  st ------------------naive way--------------------
经过分析,首先的一个思路,就是,假设某个bar是最低的一个,向左右发展,得到其面积。
哎,也就是说,对for position i,   treat height[i] as the ceiling, calculate the area

由于重复计算,代码效率不高。 代码如下

public class Solution {
   public int largestRectangleArea(int[] height) {
        int n = height.length;
        // recording the maximum area , if we assume current position bar is the
        // lowest
        int[] maxAreaHere = new int[n];
        int maxArea = 0;
        for (int i = 0; i < n; i++) {
            // we assume that current bar is the lowest
            // calculate the
            maxAreaHere[i] = height[i];
            // calculate the adjacent left areas,
            int left = i - 1;
            while (left >= 0 && height[left] >= height[i]) {
                maxAreaHere[i] += height[i];
                left--;
            }
            // calculate the adjacent right areas,
            int right = i + 1;
            while (right < n && height[right] >= height[i]) {
                maxAreaHere[i] += height[i];
                right++;
            }
            if (maxArea < maxAreaHere[i]) {
                maxArea = maxAreaHere[i];
            }
        }
        return maxArea;
    }
}

上述解法,会有TLE错误(time Limit exceed )
原因就出在 重复计算上。
网上的解法   GeeksforGeeks       Youtube.                别人的博客
思路如下:
依次加入 每个bar,加入的时候,其与之前的bar们,组成的rectangle的面积。
Solution:
Use Stack to keep track of height and start indexes
Compare current height with previous one

#1: current Larger than previous (top of height stack)
Push current height & index as candidate rectangle start position

#2: current EQUALS previous
Ignore, as largest rectangle will start from previous with same height

#3: current is less than previous
Need keep popping out previous heights, and compute the candidate rectangle with height and width (current index MINUS previous index)
Push the height and index (appropriate position) to stacks

public int largestRectangleArea(int[] height) {
        Stack<Integer> stkH = new Stack<Integer>();// stack recording the height
                                                    // of bar
        Stack<Integer> stkIndex = new Stack<Integer>();// stack recording
                                                        // correspnding index
        int maxArea = 0;
        for (int i = 0; i <  height.length; i++) { // for each length
            // if current bar is higher than previous, push
            if (stkH.isEmpty() || stkH.peek() > height[i]) {
                stkH.push(height[i]);
                stkIndex.push(i);
            } else if (stkH.peek() < height[i]) {
                // if current bar is shorter, we need pop out those longer
                // heights
                // and compute the candidatesrectangle's area and update maxArea
                int lastIndex = 0;// this index to keep track of the last index
                                    // ,which wil lbe repalceing the current
                                    // height inserting
                while (!stkH.isEmpty() && stkH.peek() < height[i]) {
                    // we need compute the size
                    lastIndex = stkIndex.pop();
                    int tmpSize = stkH.pop() * (i - lastIndex);
                    if (maxArea < tmpSize)
                        maxArea = tmpSize;
                }
                // after popping those unqualifed start position, including
                // current index,
                // we add those back , but now, current bar is the lowest from
                // lastIndex ..... i
                stkH.push(height[i]);
                stkIndex.push(lastIndex);
            }
        }
        // after the process, there might still be values in stacks, pop out
        // each other and test size
        while (!stkH.isEmpty()) {
            // we need compute the size, ( from current , down to the most left
            // bar, --- height[0]
            // the width = currentIndex(lat one) - height[i]
            // -------- just imagining we add bar of zero at most right
            int tmpSize = stkH.pop() * (height.length - stkIndex.pop());
            if (maxArea < tmpSize)
                maxArea = tmpSize;
        }
        return maxArea;
    }



Mistakes:


Learned:



------------------------------------------第二遍------------------------------------
思路同上面,那个跟人学的一样

只不过,对于2个stack,我们用一个stack<pair<int,int>>代替了。< height[i], index>, 表明了,到这个height的之前的,连贯的(小于等于该height的)最远距离。

class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int maxArea = 0;
vector<pair<int, int>>
V; // <height, index> V is left-most height in increasing order
for (int i = 0; i < heights.size(); i++) {
pair<int, int> higher{-1, -1};
while (!V.empty() && V.back().first >= heights[i]) {
higher = V.back();
V.pop_back();
}
V.push_back({heights[i], higher.first < 0 ? i : higher.second});
for (int j = 0; j < V.size(); j++) {
maxArea = max(maxArea, V[j].first * (i - V[j].second + 1));
}
}
return maxArea;
}
};

-------------------------第三遍-----------------------
再一次强调,  当现在的height[i]的值更小的时候,  我们要计算的,是在它之前的所有的面积, 而不是包括它的面积。!!!!!!!!!!!!!!!1
Tiger,   再仔细看看, 那几行代码吧。。。。





Mistakes:
1:  两个index相减, 其长度应该是要加1 的。 哎,丢人,这么SB的错误
2:刚开始的这个思想根本就是不对的。 当stack.peek() < height[i]的时候,我们应该计算的,是对于所有大于height[i]这个高度的

Learned:


86. Partition List ------------M

Given the head of a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

 

Example 1:

Input: head = [1,4,3,2,5,2], x = 3
Output: [1,2,2,4,3,5]

Example 2:

Input: head = [2,1], x = 2
Output: [1,2]

 

Constraints:

  • The number of nodes in the list is in the range [0, 200].
  • -100 <= Node.val <= 100
  • -200 <= x <= 200
A:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode hSmall, hBig;
auto tailS = &hSmall, tailB = &hBig;
while (head) {
auto tmp = head;
head = head->next;
tmp->next = nullptr;
if (tmp->val < x) {
tailS->next = tmp;
tailS = tailS->next;
} else {
tailB->next = tmp;
tailB = tailB->next;
}
}
tailS->next = hBig.next;
return hSmall.next;
}
};
Mistakes:
1: detach 一个node, 并将之放到新的list的tail上时,, 忘记把它的next节点设为null

2: 由于命名的原因(更主要的是,开始没有思考清楚,导致) 最后把tail.next = header 了。


 --------第二遍, ---思路同上----------
 Mistakes:
1:    lowerTail.next = higherHeader.next;  刚开始,SB了,写成lowerHeader.next = higherHeader.next;


Error:
 while(head!= null){
            ListNode tmp = head;
            tmp.next = null;
            head = head.next;
          
这里,这样写,顺序是不对的。 应该先 head = head.next之后,再把tmp的指针置null