1. Climbing Stairs
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
由于此题采用递归求解将会进行重复运算,利用空间重和度较高的特点,采用DP(动态规划)方法解答此题。
class Solution {
public:
int climbStairs(int n) {
if(n == 1 || n==2)
return n;
vector<int> res(n,0);
res[0]=1;
res[1]=2;
for(int i=2;i<res.size();i++)
{
res[i]=res[i-1]+res[i-2];
}
return res[n-1];
}
};
2. 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?
1337c0d2r对此题做了精彩解答,首先是易于理解的程序版本:
int singleNumber(int A[], int n) {
int count[32] = {0};
int result = 0;
for (int i = 0; i < 32; i++) {
for (int j = 0; j < n; j++) {
if ((A[j] >> i) & 1) {
count[i]++;
}
}
result |= ((count[i] % 3) << i);
}
return result;
}
对于整数来说,共有32位,记录每位1出现的个数,并对其对3取模运算,剩下的各位相加即为答案。
对此程序可以进行进一步简化,利用int32型ones,twos,threes分别记录每位出现的次数,对于threes清除对应的ones和twos,以达到相同的效果:
int singleNumber(int A[], int n) {
int ones = 0, twos = 0, threes = 0;
for (int i = 0; i < n; i++) {
twos |= ones & A[i];
ones ^= A[i];
threes = ones & twos;
ones &= ~threes;
twos &= ~threes;
}
return ones;
}
3. Maximum Subarray
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4]
,
the contiguous subarray [4,−1,2,1]
has the largest sum = 6
.
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
Solution:此题用分治法自己写了一下:
class Solution
{
public:
int subCross(int A[], int left, int right)
{
if(left == right)
return A[left];
int mid = (left+right)/2;
int leftMax=A[mid],rightMax=A[mid+1];
int sum =0;
for(int i=mid; i>=left; i--)
{
sum+=A[i];
if(sum>leftMax)
leftMax=sum;
}
sum = 0;
for(int i=mid+1; i<right+1; i++)
{
sum+=A[i];
if(sum>rightMax)
rightMax=sum;
}
return (leftMax+rightMax);
}
int maxSubArrayDevide(int A[], int left, int right)
{
if(left == right)
return A[left];
return max( max( maxSubArrayDevide(A,left,(left+right)/2) , maxSubArrayDevide(A,(left+right)/2+1,right) ),subCross(A,left,right));
}
int maxSubArray(int A[], int n)
{
return maxSubArrayDevide(A,0,n-1);
}
};
porker2008写的简洁版本如下:
class Solution {
public:
int maxSubArray(int A[], int n) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
if(n==0) return 0;
return maxSubArrayHelperFunction(A,0,n-1);
}
int maxSubArrayHelperFunction(int A[], int left, int right) {
if(right == left) return A[left];
int middle = (left+right)/2;
int leftans = maxSubArrayHelperFunction(A, left, middle);
int rightans = maxSubArrayHelperFunction(A, middle+1, right);
int leftmax = A[middle];
int rightmax = A[middle+1];
int temp = 0;
for(int i=middle;i>=left;i--) {
temp += A[i];
if(temp > leftmax) leftmax = temp;
}
temp = 0;
for(int i=middle+1;i<=right;i++) {
temp += A[i];
if(temp > rightmax) rightmax = temp;
}
return max(max(leftans, rightans),leftmax+rightmax);
}
};
4. Balanced Binary Tree
Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
Solution: 对于此题,主要是递归的求解左右深度,若差值大于1则返回false。为避免递归求解和递归求深度双重递归,采用修改引用值的方式。class Solution {
public:
bool isBalanced(TreeNode *root) {
int l=0, r=0;
if(root==NULL)
return true;
if(!isBalanced(root->right))
return false;
if(!isBalanced(root->left))
return false;
root->val=1;
if(root->right!=NULL)
root->val=1+root->right->val;
if(root->left!=NULL)
root->val=max(root->val, 1+root->left->val);
if(root->left!=NULL)
l=root->left->val;
if(root->right!=NULL)
r=root->right->val;
if(abs(r-l)>1)
return false;
return true;
}
};
5. 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.
Solution: https://oj.leetcode.com/discuss/816/minimum-path-sum-how-can-i-reduce-the-memory Given the dynamic programming formula f[i][j]=min(f[i-1][j],f[i][j-1])+grid[i][j]
:
Assume that you are populating the table row by row, the current value (f[i][j]
) will be used immediately in the calculation of f[i][j+1]
, so there is no need to store all the previous column values.
Therefore, you can do it in linear space complexity. Below is a sample code courtesy of Linfuzki@.
class Solution {
public:
int minPathSum(vector<vector<int> > &grid) {
if (grid.empty() || grid[0].empty()) return 0;
int m = grid.size(), n = grid[0].size();
vector<int> dp(n + 1, INT_MAX);
dp[1] = 0;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
dp[j + 1] = min(dp[j + 1], dp[j]) + grid[i][j];
return dp.back();
}
};
6. Sort Colors
Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note:
You are not suppose to use the library's sort function for this problem.
Follow up:
A rather straight forward solution is a two-pass algorithm using counting sort.
First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.
Could you come up with an one-pass algorithm using only constant space?
class Solution {
public:
void sortColors(int A[], int n) {
int i=-1, j=-1;
for(int p = 0; p < n; p++)
{
int v = A[p];
A[p] = 2;
if (v == 0)
{
A[++j] = 1;
A[++i] = 0;
}
else if (v == 1)
{
A[++j] = 1;
}
}
}
};
7. Merge Sorted Array
Given two sorted integer arrays A and B, merge B into A as one sorted array.
Note:
You may assume that A has enough space (size that is greater or equal to m + n) to hold additional elements from B. The number of elements initialized in A and B are m andn respectively.
Solution:
对于此题,如果不使用额外的空间,考虑从数组的最右边,也就是最大值出现的地方开始向下循环,将大值依次赋予最右边,并更改下标。
class Solution {
public:
void merge(int A[], int m, int B[], int n) {
for (int idx = m + n - 1; idx >= 0; idx--) {
if (m <= 0) {
A[idx] = B[--n];
}
else if (n <= 0) {
break;
}
else if (A[m-1] < B[n-1]) {
A[idx] = B[--n];
}
else {
A[idx] = A[--m];
}
}
}
};