Thursday, July 30, 2015

209 - Minimum Size Subarray Sum

Minimum Size Subarray Sum

Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return 0 instead.

For example, given the array [2,3,1,2,4,3] and s = 7,
the subarray [4,3] has the minimal length under the problem constraint.

click to show more practice.

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.

Hide Tags

Array Two Pointers Binary Search

Hide Similar Problems

(H) Minimum Window Substring

 

没想到合适的方法,参考别人的思路做出来的。

线性复杂度的方法是,先从头求和,直到和大于s才停下来,

然后平移,且移动起点以求缩小长度来满足和大于s,

直到移到最末尾,且不能再收缩为止,这期间的最小长度即是结果。

 

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int rst=0;
        int sz=nums.size();
        if(sz)
        {
            int idx1=0, idx2=0;
            int sum=nums[0];

            //keep adding untill sum >= s
            while(idx2<sz && sum<s)
                sum += nums[++idx2];

            //if s is even bigger than all sum, return 0
            if(idx2 == sz)
                return 0;

            //now we have a subset length to make sum >= s
            rst = idx2+1;

            //let's check for smaller length:
            int len = rst;
            while(idx2<sz)
            {
                //move idx2 --> right by 1 element, add next element to sum,
                if(idx2<sz-1)
                {
                    sum += nums[idx2+1];
                    len++;
                }
                idx2++;

                //then keep moving idx1 one by one to check if (sum - nums[idx1]) > s
                while((sum-nums[idx1])>=s)
                {
                    sum -= nums[idx1++];
                    len--;
                }
                //untile smaller, and updating rst at the same time.
                rst = (len<rst)?len:rst;               
           }
        }
        return rst;
    }
};

4 ms.

 

关于 nlgn 的解法,也就是折半查找的方法,稍后再写。

064 - Minimum Path Sum

Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Hide Tags

Array Dynamic Programming

Hide Similar Problems

(M) Unique Paths (H) Dungeon Game

 

典型DP,从右下往左上计算,亦或是从左上往右下计算都可以。

每一步取可以到达该格子的两个相邻格子之间小的那个,加上自己的值即可。

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int rst = 0;
        int sz = grid.size();
        if(sz)
        {
            int zz = grid[0].size();
            if(zz)
            {
                for(int ii=sz-1; ii>=0; ii--)
                {
                    for(int jj=zz-1; jj>=0; jj--)
                    {
                        if((jj==zz-1)&&(ii==sz-1))
                            continue;
                        if(jj==zz-1)
                            grid[ii][jj] += grid[ii+1][jj];
                        else if(ii==sz-1)
                            grid[ii][jj] += grid[ii][jj+1];
                        else
                            grid[ii][jj] += min(grid[ii][jj+1], grid[ii+1][jj]);

                    }
                }
                rst = grid[0][0];
            }
        }
        return rst;
    }
};

28 ms.

090 - Subsets II

Subsets II

Given a collection of integers that might contain duplicates, nums, return all possible subsets.
Note:
  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,2], a solution is:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

Hide Tags
Array Backtracking
比较偷懒的做法是在第一题的结果上,再sort一下,用unique去重。
仔细观察一下push的过程,会发现,
当处理完一个起点的递归之时,再其下一层的调用返回之前,
想要避免重复的结果,就是直接跨到下一个不同的元素上去,

例如 [1, 2, 2, 3]
当start是1的时候,假设要处理的count是2,即,只取两个数组来组合,
递归调用进去start’ 是第一个2,这时候满足了两个数字,
所以再次递归进去就push当前这个组合到结果区了。
然后返回,如果这时候继续循环,start’’ 是第二个2,就会出现重复的 [1, 2] 了
所以需要跳过第二个 2, 直到遇到 3。
这样做并不影响 [2, 2],因为从2进来,并没有先跳过,而是处理完了才跳过,
所以就算有n个2,都可以处理。
配合count,对于重复的元素,就可以产生完全的组合了。

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<vector<int>> rst;
        vector<int> buf;
        rst.push_back(buf);


        int sz = nums.size();
        if(sz)
        {
            sort(nums.begin(), nums.end());
            for(int nn=1; nn<=sz; ++nn)
                build(nums, sz, rst, buf, nn, 0, 0);
        }


        return rst;
    }
   
    void build(vector<int>& nums, int sz, vector<vector<int>>& rst,
                    vector<int>& buf, int count, int taken, int start)
    {
        if(taken==count)
            rst.push_back(buf);
        else
        {
            int end=sz-count+taken;
            for(int ii=start; ii<=end; ++ii)
            {
                buf.push_back(nums[ii]);
                build(nums, sz, rst, buf, count, taken+1, ii+1);
                buf.pop_back();
               
                while((ii<=end)&&(nums[ii]==nums[ii+1]))
                    ii++;

            }
        }
        return;
    }
};


12 ms.



讨论区有个帖子,提到了三种解法,可以参考
下面是他提到的递归,写得更简洁:

//recursive 8ms
vector<vector<int>> res;
int n;
void generate(vector<int>& num, vector<int>& tmp, int k) {
   
res.push_back(tmp);  //每次进来,先把已经取到的元素作为一个结果push进去

    for (int i = k; i < n; i++) {
        tmp.push_back(num[i]);      //在已经走到的元素后面继续追加
        generate(num, tmp, i + 1);  //递归进去,
        tmp.pop_back();
        while (i < n - 1 && num[i] == num[i + 1]) {  //跳过重复的部分
            i++;
        }
    }
}


vector<vector<int>> subsetsWithDup3(vector<int>& nums) {
    n = nums.size();
    vector<int> tmp;
    sort(nums.begin(), nums.end());
    generate(nums, tmp, 0);
    return res;
}

Wednesday, July 29, 2015

078 - Subsets

Subsets

Given a set of distinct integers, nums, return all possible subsets.
Note:
  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

Hide Tags
Array Backtracking Bit Manipulation

注意要求,需要先对输入的数据排个序。
然后依次组合即可。
至于bit操作,应该是每个bit位表示输入的vector里的对应的数字是否被选中,
但是需要考虑bit的长短,移位会不会溢出等等,实际上并不是非常完美的一个选择。
讨论区里有用bit解这道题的,case应该是都通过了,但这个问题还是存在的。(参考帖子

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> rst;
        vector<int> buf;
        rst.push_back(buf);


        int sz = nums.size();
        if(sz)
        {
            sort(nums.begin(), nums.end());
            for(int nn=1; nn<=sz; ++nn)  //依次创建从1一个元素到sz个元素的所有组合
                build(nums, sz, rst, buf, nn, 0, 0);
        }
        return rst;
    }

    void build(vector<int>& nums, int sz, vector<vector<int>>& rst,
                    vector<int>& buf, int count, int taken, int start)
    {
        if(taken==count)
            rst.push_back(buf);
        else
        {
            int end=sz-count+taken;
            for(int ii=start; ii<=end; ++ii)
            {
                buf.push_back(nums[ii]);
                build(nums, sz, rst, buf, count, taken+1, ii+1);
                buf.pop_back();
            }
        }
        return;
    }

};


8 ms.




073 - Set Matrix Zeroes

Set Matrix Zeroes

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.

click to show follow up.

Follow up:

Did you use extra space?
A straight forward solution using O(mn) space is probably a bad idea.
A simple improvement uses O(m + n) space, but still not the best solution.
Could you devise a constant space solution?

Hide Tags

Array

 

要求in place,所以必须用已经存在的空间,也就是matrix里头的单元。

当找到第一个0的时候,就可以用它所在的行和列作为buffer,

把其他的零所在的行列,也就是需要置0的行列,在这两个buffer里,标识出来。

注意最后置位的时候,要先留住buffer里的内容,不然会把整个矩阵都置为0.

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int sz=matrix.size();
        if(sz)
        {
            int zz=matrix[0].size();
            if(zz)
            {
                for(int ii=sz-1; ii>=0; ii--)
                    for(int jj=zz-1; jj>=0; jj--)
                       if(0 == matrix[ii][jj])
                            return clean(matrix, ii, jj, sz, zz); //直接return就好
            }
       }
    }
   
    void clean(vector<vector<int>>& matrix, int buf_row, int buf_col, int sz, int zz)
    {
        for(int ii=buf_row-1; ii>=0; ii--)
            for(int jj=zz-1; jj>=0; jj--)
                //reuse the row/col of first zero as a buffer for zeros
                if((buf_col!=jj)&&(0 == matrix[ii][jj]))
                {
                    matrix[buf_row][jj]=0;
                    matrix[ii][buf_col]=0;
                }

        //now set all zeros
        for(int ii=sz-1; ii>=0; ii--)
            if((ii!=buf_row)&&(0==matrix[ii][buf_col])) //先不要set用作缓冲区的行
                for(int jj=zz-1; jj>=0; jj--)
                    matrix[ii][jj] = 0;

        for(int jj=zz-1; jj>=0; jj--)
            if(0==matrix[buf_row][jj])
              for(int ii=sz-1; ii>=0; ii--)
                matrix[ii][jj] = 0;

        for(int jj=zz-1; jj>=0; jj--) //单独set用做缓冲区的行,不然中间的循环会多set
            matrix[buf_row][jj] = 0;

        return;
    }
};

074 - Search a 2D Matrix

Search a 2D Matrix

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.
For example,
Consider the following matrix:
[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]

Given target = 3, return true.
Hide Tags
Array Binary Search
Hide Similar Problems
(M) Search a 2D Matrix II


二分查找,先二分行,后二分行内。
当然也可以不递归,还可以行列同时二分
看到一个更漂亮的解法:
因为数组下一行首比上一行尾大,所以实际上可以看成一个一维数组来进行二分法。

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int sz = matrix.size();
        if(sz)
        {
            int zz = matrix[0].size();
            if(zz)
            {
                if((target<matrix[0][0])||target>matrix[sz-1][zz-1])
                    return false;


                int idx=-1;
                if(false == colSearch(matrix, sz, zz, 0, sz-1, target, idx))
                {
                    //if(-1==idx)
                    //    return false;
                    //else
                        return rowSearch(matrix[idx], 0, zz-1, target);
                }
                return true;
            }
        }
    }
   
    bool colSearch(vector<vector<int>>& mtx, int m, int n,

                      int start, int end, int tgt, int& idx)
    {
        if(start>end)   //should not be here
        {
            idx = -1;
            return false;
        }
        int ms = mtx[start][0];
        int me = mtx[end][0];


        if(tgt==ms) //no need for further searching
        {
            idx = start;
            return true;
        }
        if(tgt==me) //no need for further searching
        {
            idx = end;
            return true;
        }


        if(tgt>me) //in last row
        {
            idx = end;
            return false;
        }
        if((start==(end-1))&&(tgt<me)&&(tgt>ms))    //in other rows
        {
            idx = start;
            return false;
        }

       
        int mid = (start+end)/2;
        if(tgt<mtx[mid][0])
            return colSearch(mtx, m, n, start, mid-1, tgt, idx);
        else
            return colSearch(mtx, m, n, mid, end, tgt, idx);
    }
   
    bool rowSearch(vector<int>& row, int start, int end, int tgt)
    {
        if(start>end)
            return false;


        int ms = row[start];
        int me = row[end];
        if((tgt==ms)||(tgt==me))
            return true;


        if((start==(end-1))&&(tgt<me)&&(tgt>ms))
            return false;


        int mid = (start+end)/2;
        if(row[mid] == tgt)
            return true;


        if(tgt<row[mid])
            return rowSearch(row,start,mid-1,tgt);
        else
            return rowSearch(row,mid+1,end,tgt);
    }
};


12 ms.







Tuesday, July 28, 2015

154 - Find Minimum in Rotated Sorted Array II

Find Minimum in Rotated Sorted Array II

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

Would this affect the run-time complexity? How and why?

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

The array may contain duplicates.

Hide Tags

Array Binary Search

Hide Similar Problems

(M) Find Minimum in Rotated Sorted Array

就是在153的基础上,加上过滤重复的值。

刚开始想的是,从mid向两边过滤,发现不能解决问题,

所以换个方向,从start 和 end 向中间过滤,

这样避免了mid的值等于start或者end的值,搞定。

class Solution {
public:
    int findMin(vector<int>& nums) {
        int rst;
        find(nums, 0, nums.size()-1, rst);
        return rst;
    }

    void find(vector<int>& nums, int start, int end, int& min)
    {
        if(start>end)
            return;

        //in case duplicated value
        while((start<end)&&(nums[start] == nums[start+1]))
            start++;

        while((start<end)&&(nums[end] == nums[end-1]))
            end--;

        int mid = (start+end)/2;
        int last = (start<mid)?(mid-1):end;
        int next = (end>mid)?(mid+1):start;

        if((start==end)||(nums[mid]<nums[last]))
            min = nums[mid];
        else if(nums[mid]<nums[end])
            find(nums, start, last, min);
        else
            find(nums, next, end, min);
        return;
    }   
};

8 ms.

062 - Unique Paths

Unique Paths

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?

Above is a 3 x 7 grid. How many possible unique paths are there?

Note: m and n will be at most 100.

Hide Tags

Array Dynamic Programming

Hide Similar Problems

(M) Unique Paths II (M) Minimum Path Sum (H) Dungeon Game

 

起先写了个递归的,断然是超时了,

改成动规的,从终点推回到起点,ok了,0ms。

class Solution {
public:
    int uniquePaths(int m, int n)
    {
        int* matrix = new int[m*n];
        memset(matrix, 0, m*n*sizeof(int));
        matrix[(m-1)*n + n-1]=1;
        for(int ii=m-1; ii>=0; ii--)
        {
            for(int jj=n-1; jj>=0; jj--)
            {
                int idx = (ii)*n + jj;
                if(jj<n-1)
                    matrix[idx] += matrix[idx+1];

                if(ii<m-1)
                    matrix[idx] += matrix[idx+n];

            }
        }
        int rst = matrix[0];
        if(matrix)
            delete[] matrix;
        return rst;
    }

 

/********** recursive call, timeout ***********/

    int uniquePaths_timeout(int m, int n) {
        return go(m, n, 0, 0);
    }
   
    int go(int m, int n, int x, int y)
    {
        int rst=0;
       
        if((x==(n-1))&&((0-y)==(m-1)))
            return 1;
       
        if(x<(n-1))
            rst += go(m, n, x+1, y);
       
        if((0-y)<(m-1))
            rst += go(m, n, x, y-1);
        return rst;
    }

};

153 - Find Minimum in Rotated Sorted Array

Find Minimum in Rotated Sorted Array

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

You may assume no duplicate exists in the array.

Hide Tags

Array Binary Search

Hide Similar Problems

(H) Search in Rotated Sorted Array (H) Find Minimum in Rotated Sorted Array II

当然是二分查找,只是查找的判断方法变了一下,

如果同时小于last和next,则为正解,如果切分到start==end,也就是它;

如果小于end的值,那么最小值在左边,反之在右边。

class Solution {
public:
    int findMin(vector<int>& nums) {
        int rst;
        find(nums, 0, nums.size()-1, rst);
        return rst;
    }
   
    void find(vector<int>& nums, int start, int end, int& min)
    {
        if(start>end)
            return;
        int mid = (start+end)/2;
        int last = (start<mid)?(mid-1):end;
        int next = (end>mid)?(mid+1):start;

        if((start==end)||(nums[mid]<nums[last]))  //不用判断是不是还大于next
            min = nums[mid];

        else if(nums[mid]<nums[end])
            find(nums, start, mid-1, min);

        else
            find(nums, mid+1, end, min);

        return;
    }
};

222 - Count Complete Tree Nodes

Count Complete Tree Nodes

Given a complete binary tree, count the number of nodes.

Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2hnodes inclusive at the last level h.

Hide Tags

Tree Binary Search

 

刚开始直接写了个简单的递归,递归计算左右子树,

虽然逻辑上没有问题,但是递归超时

(后来看到有人加了左右相等时直接计算2的幂,可以通过test case)

看题目的提示,是用二分查找,也就是要快速断定最后一个节点的位置。

于是想到就是找root左子的最右边分支,以及右子的最左边分支,

这两个都可以是中点,于是写了一个find函数,找到两个中点,

依照两个中点的深度判断应该选择走左边还是右边。

但是性能并不好,要124ms,把递归调用改成了while循环之后,减少到112ms。

仔细又看了看,实际上并不需要找两个中点,只用右边的就好了,

因为是向左聚拢的嘛,去掉冗余的左边中点,简化判断条件之后,达到了76ms。

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/

class Solution {
public:
    int countNodes(TreeNode* root)
    {
        TreeNode* p = root;
        int num = 0;
       
        if(root)
        {
            num = 1;
           
            int hh=0;
            while(p)
                hh++, p = p->left; //get height

            if(1==hh)
                return num;
           
            while(root)
            {
                int hr=0;   //find right mid, go right, then keep going left.
                p = root->right;
                while(p)
                    hr++, p = p->left;
       
                //last 2nd level
                if(2==hh)
                    return (hr)?((num<<1) +1):(num<<1);
//this is why right mid

                if((hr==(hh-1))&&(root->right))         //this is why right mid
                    num = (num<<1)+1,   root = root->right; //右子索引=parent*2+1
                else if(root->left)
                    num = (num<<1),     root = root->left;  //左子索引=parent*2
                else
                    ;
                hh--;
            }
            //find(root, hh, num);  //recursive call, time-costing.
        }
        return num;
    }

 

/* ----- ONLY FOR Recursive calls ----- */

    void find(TreeNode* root, int hh, int& num)
    {
        int hl=0, hr=0;
       
        TreeNode* p = root->left;
        while(p)
            hl++, p = p->right;

        p = root->right;
        while(p)
            hr++, p = p->left;

        //last 2nd level
        if(2==hh)
        {
            if(hl&&(!hr))
                num = (num<<1);
            else
                num = (num<<1)+1;
            return;
        }
       
        if((hr&&(hr==(hh-1)))&&(root->right))
        {
            num = (num<<1)+1;
            return find(root->right, hh-1, num);
        }
        if(root->left)
        {
            num = (num<<1)+0;
            return find(root->left, hh-1, num);
        }
        return;
    }

/* ----- this solution works but takes too much time  ----- */
    int countNodes_timeout_solution(TreeNode* root) {
        int rst = 0;
        if(root)
        {
            if(root->left)
                rst += countNodes(root->left);
            if(root->right)
                rst += countNodes(root->right);

            rst += 1;
        }
        return rst;
    }
};

发在讨论区了。

Thursday, July 23, 2015

081 - Search in Rotated Sorted Array II

Search in Rotated Sorted Array II

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

Would this affect the run-time complexity? How and why?

Write a function to determine if a given target is in the array.

Hide Tags

Array Binary Search

Hide Similar Problems

(H) Search in Rotated Sorted Array

 

在033的基础上加上了可以出现重复的值,

带来的问题是,begin/end 跟 mid的值可能一样,从而影响判断。

所以加两个处理,从mid分别向左右检查直到遇到不同的值,

这样就避免了上述情形,但是递归的条件里要加上等号。

复杂度上没有本质变化吧,但添加的处理可能会有增加,取决于多少个重复的值了。

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        int sz = nums.size();
        if(sz)
            return (-1!=bsearch(nums, target, 0, sz-1));
        return false;
    }
   
   
    int bsearch(vector<int>& nums, int tgt, int begin, int end)
    {
        if(begin>end)
            return -1;
           
        if(tgt == nums[begin])
            return begin;
        if(tgt == nums[end])
            return end;
           
        int mid = (begin+end)/2;
        if(tgt == nums[mid])
            return mid;
       
        int leftend = mid;
        while((leftend>begin)&&(nums[leftend]==nums[mid]))
            leftend--;

        int rightbegin = mid;
        while((rightbegin<end)&&(nums[rightbegin]==nums[mid]))
            rightbegin++;

        if(((nums[begin]<nums[leftend])&&((tgt>nums[begin])&&(tgt<=nums[leftend])))
            || ((nums[begin]>nums[leftend])&&((tgt<=nums[leftend])||(tgt>nums[begin]))))
            return bsearch(nums, tgt, begin+1, leftend);

        else if(((nums[rightbegin]<nums[end])&&((tgt>=nums[rightbegin])&&(tgt<nums[end])))
            || ((nums[rightbegin]>nums[end])&&((tgt>=nums[rightbegin])||(tgt<nums[end]))))
            return bsearch(nums, tgt, rightbegin, end-1);
       
        else
            return -1;
    }

};

8 ms.

033 - Search in Rotated Sorted Array

Search in Rotated Sorted Array

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Hide Tags

Array Binary Search

Hide Similar Problems

(M) Search in Rotated Sorted Array II (M) Find Minimum in Rotated Sorted Array

 

再一次说明,在简单的题目上改变一点点,解答可能就麻烦不少。

因为数组rotate过了,所以二分查找的时候,

简单判断大于等于小于中间值就不够了,同样是大于中间值,两边都有可能。

那要判断分出来的一半是什么情况,在不在它的范围内,

因为加入了这个判断,所以还需要补一个,都不在左右范围内,返回-1。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int sz = nums.size();
        if(sz)
            return bsearch(nums, target, 0, sz-1);
        return 0;
    }
   
   
    int bsearch(vector<int>& nums, int tgt, int begin, int end)
    {
        if(begin>end)
            return -1;
           
        if(tgt == nums[begin])
            return begin;
        if(tgt == nums[end])
            return end;
           
        int mid = (begin+end)/2;
        if(tgt == nums[mid])
            return mid;
           
        if(((nums[begin]<nums[mid])&&((tgt>nums[begin])&&(tgt<nums[mid])))
            || ((nums[begin]>nums[mid])&&((tgt<nums[mid])||(tgt>nums[begin]))))
            return bsearch(nums, tgt, begin+1, mid-1);

        else if(((nums[mid]<nums[end])&&((tgt>nums[mid])&&(tgt<nums[end])))
            || ((nums[mid]>nums[end])&&((tgt>nums[mid])||(tgt<nums[end]))))
            return bsearch(nums, tgt, mid+1, end-1);
       
        else
            return -1;

    }
};

4 ms

048 - Rotate Image

Rotate Image

You are given an n x n 2D matrix representing an image.

Rotate the image by 90 degrees (clockwise).

Follow up:
Could you do this in-place?

Hide Tags

Array

 

矩阵旋转的方法:

先左右互换,然后

顺时针则左上右下对角互换,

逆时针则左下右上对角互换。

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        if(n)
        {
            for(int ii=0; ii<n; ++ii)
                for(int jj=0; jj<(n/2); ++jj)
                    swap(matrix[ii][jj], matrix[ii][n-1-jj]);

            for(int ii=0; ii<n; ++ii)
                for(int jj=0; jj<(n-ii); ++jj)
                    swap(matrix[ii][jj], matrix[n-1-jj][n-1-ii]);
        }
    }
};

4 ms.

Wednesday, July 22, 2015

057 - Insert Interval

Insert Interval

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).

You may assume that the intervals were initially sorted according to their start times.

Example 1:
Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].

Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16].

This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].

Hide Tags

Array Sort

Hide Similar Problems

(H) Merge Intervals

 

这题其实就是 056 加上一行代码:先把这个newInterval 直接push_back到 intervals里去,

然后就完全是 056 的merge了, 跑出来588 ms.

当然也可以手工insert,这样merge之前就不用sort,但是insert的也不见得就快多少。

 

另外还写了一个直接解的方法:

既然是已经排过序的,那就顺序读取吧,只是每读取一个,都要跟newInterval 比较,

除非newInterval 已经插入完毕了,所以用了两个标记 done_a, done_b,记录值且作为标记

然后就是看具体插入什么值了,这个比较就比较啰嗦了,三对值的比较:

newInterval, intervals[ii],  和已经放入结果的最后一对,

start end 逐个比较,确认本次应该push的 a, b;

如果无需push,把copyme置为0;

如果还需要修改已经push过的记录,将copyme置为-1。

全部检查完毕之后,还需要确认是否newInterval完全没有插入过,没有就补上。

/**
* Definition for an interval.
* struct Interval {
*     int start;
*     int end;
*     Interval() : start(0), end(0) {}
*     Interval(int s, int e) : start(s), end(e) {}
* };
*/

class Solution {
public:
    vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
        vector<Interval> rst;
        int done_a = -1, done_b = -1, done=0;
        int sz=intervals.size();
        if(sz)
        {
            for(int ii=0; ii<sz; ++ii)
            {
                int copyme = 1;

                //a,b是本次需要push的值,预置为新插入的
                int a=newInterval.start, b=newInterval.end;

                //当前取出来的一对值。
                int ss=intervals[ii].start, ee=intervals[ii].end;
               
                if(-1 == done_a)                       //还没merge过起点
                {
                    if(a < ss)                         //新插入的更小,用新的
                           done_a = a;
                    else if((a >= ss)&&(a <= ee))      //当前取出的小,且包含新插入的起点
                        a = ss, done_a = ss;
                    else                               //跟新插入的不重叠,不要置done_a
                        a = ss, b = ee;                //这里已经改过 b 的值了,所以后面不需要处理了
                }

                if(-1 != done_a)                       //已经置了done_a
                {

                    if(-1 == done_b)                   //如果done_b还没有置,那就该处理done_b了
                    {
                        if(b < ss)                     //新插入的end小于取出的起点,ii减一,下次处理取出来的
                            ii--;
                        else if((b >= ss)&&(b < ee))   //新插入的end小于取出的end,用取出的end
                            b = ee;
                        else                           //新插入的end更大,就用新的end
                            ;
                        done_b = b;                    //置done_b,表示插入完毕
                    }

                    else                               //--此时已经完成插入,但是取出的可能跟插入的还会有交叠
                    {
                        if((done_a<=ss)&&(done_b>=ee)) //--取出的被完全包含,不用copy了
                            copyme = 0;
                        else if(done_b<ss)             //--取出的在已经插入的范围之外,用取出的
                            a = ss, b = ee;
                        else                           //--取出的起点在已经插入的范围内,但end更大,要更新
                            b = ee, copyme = -1;       //--但不是push新的一对值,而是更新上次压入的结果
                    }

                }

                if(-1 == copyme)
                    rst[done-1].end = b;
                   
                if(1 == copyme)
                {
                    rst.push_back(Interval(a, b));
                    done++;
                }
            }
        }
        if((-1 == done_a))                             //如果全程都没用到,done_a肯定还是初始值,补上新插入的
            rst.push_back(newInterval);

        return rst;
    }
};

580 ms.

看了一下统计,Python 那叫一个快。。。

056 - Merge Intervals

Merge Intervals

Given a collection of intervals, merge all overlapping intervals.

For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

Hide Tags

Array Sort

Hide Similar Problems

(H) Insert Interval

 

先按照起点排序,再扫描排序后的结果,

因为起点都排过序了,所以后一个的start肯定不会更小,那么只需要处理两种情况:

1. 后面的start,小于前一个的终点,

    此时如果后一个的end大于前一个的end,就扩大前一个的end,否则略过;

2. 后面的start,大于前一个的终点,

    这就意味着出现不连续的情况了,那么只需要push一个新的struct到结果里,

    再重复这些步骤就好了。

另外要写个排序规则。

 

/**
* Definition for an interval.
* struct Interval {
*     int start;
*     int end;
*     Interval() : start(0), end(0) {}
*     Interval(int s, int e) : start(s), end(e) {}
* };
*/
bool cmp1(Interval a, Interval b)
{
    return (a.start)<(b.start);
}

class Solution {
public:
    vector<Interval> merge(vector<Interval>& intervals) {
        vector<Interval> rst;
        int sz=intervals.size();
        if(sz)
        {
            sort(intervals.begin(), intervals.end(), cmp1);

            int done=0;
            rst.push_back(intervals[0]);
            for(int ii=1; ii<sz; ++ii)
            {
                while((ii<sz)&&((rst[done].end)>=(intervals[ii].start)))
                {
                    if((rst[done].end)<(intervals[ii].end))
                        rst[done].end = intervals[ii].end;
                    ii++;
                }
                if(ii<sz)
                {
                    rst.push_back(intervals[ii]);
                    done++;
                }
            }
        }       
        return rst;       
    }
};

 

起初还想过双排序,直觉双排序能带来更多的好处,

先按照每一对的起点排序,再按终点排序,然后对位合并,

然后分析,每个位置取两个结果的最大范围;

再然后才是扫描分析结果,更新end或者push新的struct,

后来发现其实完全不必要,因为分析的时候起点都是取两次排序里小的那个,

所以实际上只要一次排序就够了。

但郁闷的是,删掉了一次排序,以及一次vector复制,居然时间没啥变化。。。

(用临时变量替换 (rst[done].end) 之后提高了12ms,注意,done++之后也要更新临时变量)

Monday, July 20, 2015

003 - Longest Substring Without Repeating Characters

Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.

Hide Tags

Hash Table Two Pointers String

Hide Similar Problems

(H) Longest Substring with At Most Two Distinct Characters

 

用一个256个int的数组辅助统计重复出现的字母,初始化为 -1,

如果出现了就存放该字母在字符串中的下标,遇到大于 –1 的就是重复出现的字母了。

至于这个重复出现的字母是否影响统计,需要一个辅助的变量来表示从哪里算起,

所以用了一个start,每当确认是有影响的重复字母,

就把该字母上次出现的下标,也就是辅助数组里存的那个下标,更新为新的起点(但不包括它),

    同时把统计值重置为 当前下标减去上次出现的下标,也就是从新起点之后的字母到现在的自己;

但如果新发现的重复字母,其辅助数组里存的上一次出现的下标,早于这个start,就不用更新了,

    因为起点之后并不包括该字母,应该视同第一次出现,直接将统计值sum++。

更新了sum之后,检查是否大于最终的结果total,如果是则更新total。

从头走到尾,一遍即可完成处理。

 

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int pre=-1, start=-1, idx=-1;
        int sum=0, total=0, len=s.length();

        array<int, 256> taken;
        taken.fill(-1);         //辅助数组全部初始化为 -1,

                                //不要用 int taken[256]={-1}; 这只能初始化第一个!!

        for(int ii=0; ii<len; ++ii)
        {
            idx = s[ii];
            pre = taken[idx];   //上一次出现的下标
            taken[idx] = ii;    //更新记录为本次出现的下标

            if(pre>start)       //在start之后,会影响统计结果
            {
                sum = ii - pre; //重算sum
                start = pre;    //更新起点
            }

            else
                sum++;

            if(total < sum)
                total = sum;
        }
        return total;
    }
};

16 ms.

关于 for 循环的加加减减

i--操作本身会影响CPSR(当前程序状态寄存器)

CPSR常见的标志有

N(结果为负), Z(结果为0)C(有进位)O(有溢出)

i >= 0,可以直接通过Z标志判断出来。 

i++操作也会影响CPSR(当前程序状态寄存器)

但只影响O(有溢出)标志这对于i < n的判断没有任何帮助

所以还需要一条额外的比较指令,也就是说每个循环要多执行一条指令

原文在此

179 - Largest Number

Largest Number

Given a list of non negative integers, arrange them such that they form the largest number.

For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.

Note: The result may be very large, so you need to return a string instead of an integer.

Credits:
Special thanks to @ts for adding this problem and creating all test cases.

Hide Tags

Sort

先把数字都转成字符串,

然后做个特殊的排序,使得按照需要的大小排列,

最后把字符串串起来就好了。

但是写排序函数的时候,一开始思路有问题,陷入到很具体的数字比较了,

例如 (12, 121) (824, 8247) (2, 2281) ….

各种比较条件堆起来,排序函数写得巨复杂,越看越不对,铁定是思路错了。

后来想到,目的就是要组合出来的数字更大嘛,

那就把比较的两个字符串正串反串比一下不就好了么!

果然,一行就搞定了。。。

 

bool cmpstr (string a,string b)
{
    return (a+b)<(b+a); //这一贱的风情。。。
}

class Solution {
public:
    string largestNumber(vector<int>& nums) {
        vector<string> buf;
        string rst="";

        for(int ii=nums.size()-1; ii>=0; ii--)
            buf.push_back(to_string(nums[ii]));

        sort(buf.begin(), buf.end(), cmpstr);

        if('0' == (buf[buf.size()-1])[0])
            return "0";

           
        for(int ii=buf.size()-1; ii>=0; ii--)
            rst += buf[ii];
       
        return rst;
    }
};

8 ms.

 

如果是C,就没有sort函数可以用了,

但是。。。还有别的:用qsort的解法,原帖在此。

046 - Permutations

Permutations

Given a collection of numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].

Hide Tags

Backtracking

Hide Similar Problems

(M) Next Permutation (H) Permutations II (M) Permutation Sequence (M) Combinations

题目倒简单,穷尽各种组合就是了。

但是遇到一个怪异的问题,蓝色的部分,如果去掉,就会出问题。

调试发现,new出来的数组,居然有时候不会是全0?!

很奇怪,自己写了段代码试了一下,确实有这个情况发生,强制清零之后就没有问题了。

补一课:new 出来的东西,真的不一定会初始化的。。。

参考: default initialization, value initialization

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> rst;
        int sz = nums.size();
        if(sz)
        {
            vector<int> group;
            int used = 0;
            int* inuse = new int[sz];
            memset(inuse, 0, sz*sizeof(int));
            build(rst, group, nums, sz, inuse, used);
        }  
        return rst;
    }
private:
    void build(vector<vector<int>>& rst, vector<int>& group, vector<int> nums, int sz, int* inuse, int used)
    {
        for(int ii=0; ii<sz; ++ii)
        {
            if(0 == inuse[ii])
            {
                group.push_back(nums[ii]);
                inuse[ii]=1;
                used++;
               
                if(used==sz)
                    rst.push_back(group);
                else
                    build(rst, group, nums, sz, inuse, used);
               
                used--;
                inuse[ii]=0;
                group.pop_back();
            }
        }
    }
};

16 ms.

080 - Remove Duplicates from Sorted Array II

Remove Duplicates from Sorted Array II

Follow up for "Remove Duplicates":
What if duplicates are allowed at most twice?

For example,
Given sorted array nums = [1,1,1,2,2,3],

Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn't matter what you leave beyond the new length.

Hide Tags

Array Two Pointers

与 1 不同的是,如果有重复的,可以保留两个重复的值。

1 的基础上改的,加入了一点处理:

如果while结束之后,jj的位置比ii的位置“远”,则说明有重复的值

那么就在ii的位置复制一份,再一起向前。

“远”多少呢?就是超过ii跟jj之间的已有的距离,所以加一个变量保存两者间的offset即可。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int ii = 0;
        if(nums.size())
        {
            int offset=0;                   //distance between ii and jj
            for(int jj=0; jj<nums.size(); )
            {
                nums[ii++] = nums[jj++];
                while((nums[ii-1] == nums[jj])&&(jj<nums.size()))
                    jj++;
               
                if(jj>(ii+offset))          //if jj covers more than 1 duplicate value
                {
                    nums[ii] = nums[ii-1];  //duplicate the second one
                    ii++;                   //move to next for new value
                    offset = jj-ii;         //update distance
                }

             }
        }
        return ii;
    }
};

16 ms

026 - Remove Duplicates from Sorted Array

Remove Duplicates from Sorted Array

Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

For example,
Given input array nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the new length.

Hide Tags

Array Two Pointers

 

两个下标,遇到重复的jj向前,直到遇到新值才复制新值。

注意jj向前的时候需要保护。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int ii = 0;
        if(nums.size())
        {
            for(int jj=0; jj<nums.size(); )
            {
                nums[ii++] = nums[jj++];
                while((nums[ii-1] == nums[jj])&&(jj<nums.size()))
                    jj++;
             }
        }
        return ii;
    }
};

32 ms.

137 -Single Number II

Single Number II

Given an array of integers, every element appears three times except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Hide Tags

Bit Manipulation

Hide Similar Problems

(M) Single Number

用数组统计每个bit位的出现次数,对3求余,

所有出现过三次的数字的bit位都会被去掉,

剩下的bit位就是只出现过依次的那个数字,重新组合即可。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int sz = nums.size();
        int rst = 0;
        if(sz)
        {
            int bits[32]={0};
            for(int ii=0; ii<sz; ++ii)
            {
                int num = nums[ii];
                for(int bb=0; bb<32; ++bb)
                {
                    if(num&(1<<bb))
                        bits[bb]++;

                }
            }
           
            for(int bb=0; bb<32; ++bb)
            {
                if((bits[bb])%3)
                    rst |= (1<<bb);

            }
        }
        return rst;
    }
};

16 ms.

Sunday, July 19, 2015

077–Combinations

Combinations

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],
]

Hide Tags

Backtracking

Hide Similar Problems

(M) Combination Sum (M) Permutations

用bfs做的,依次取值罗列所有组合。


class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> rst;
        vector<int> group;
        if(k&&k<=n)
            build(rst, group, 1, n, k-1);
        return rst;
    }
private:
    void build(vector<vector<int>>& rst, vector<int>& group, int begin, int n, int k)
    {
        for(int ii=begin; ii<=n; ++ii)
        {
            group.push_back(ii);
            if(!k)
                rst.push_back(group);

            else
                build(rst, group, ii+1, n, k-1);

            group.pop_back();
        }
        return;
    }
};


12 ms.