leetcode300. Longest Increasing Subsequence
Given an unsorted array of integers, find the length of longest increasing subsequence.For example, Given [10, 9, 2, 5, 3, 7, 101, 18], The longest
increasing subsequence is [2, 3, 7, 101], therefore the length is 4.
Note that there may be more than one LIS combination, it is only
necessary for you to return the length.Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
分析:
建立一个和nums数组等长的dp数组,dp数组dp[i]的值表示nums[i]处可以构成的最长字串的长度,也就是说,在i下标前面的所有nums值当中,找到所有比nums[i]小的,且dp值最大的那个值,然后加1,然后最长递增子序列的长度为所有dp[i]当中最大的值。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
if(n == 0)
return 0;
vector<int> dp(n);
dp[0] = 1;
int ans = 1;
for(int i = 1; i < n; i++) {
int temp = 0;
for(int j = i - 1; j >= 0; j--) {
if(nums[j] < nums[i]) {
temp = max(temp, dp[j]);
}
}
dp[i] = temp + 1;
ans = max(ans, dp[i]);
}
return ans;
}
};
上述DP方法为O(N^2),有一个比较难想到的方法为O(NlogN)
方法为维护一个数组vector v,将nums[0]加入数组,对于每一个来的数nums[i],如果大于v.back(),就将它push入数组,否则,就找到第一个比这个数大的位置,将该位置的数字替换为nums[i],最终返回v数组的长度就是最长字串的长度。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
if(n == 0)
return 0;
vector<int> v;
v.push_back(nums[0]);
for(int i = 1; i < n; i++) {
if(nums[i] > v.back()) {
v.push_back(nums[i]);
} else {
*lower_bound(v.begin(), v.end(), nums[i]) = nums[i];
}
}
return v.size();
}
};
leetcode 120. Triangle
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
[[2],
[3,4],
[6,5,7],
[4,1,8,3]]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
分析:
要找到一条和最小的路径,可以采用自底向上,从左到右的顺序更新状态转移方程:triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]);最后只需直接return triangle[0][0]即可。
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
for(int i = triangle.size() - 2; i >= 0; i--) {
for(int j = 0; j <= i; j++) {
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1]);
}
}
return triangle[0][0];
}
};
leetcode 198. House Robber
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
分析:
我们可以创建一个数组dp[n]表示从0~n-1家能够抢到的最大值,且满足
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
dp[i] = max(dp[i – 2] + nums[i], dp[i – 1]);
在进行选择时,robber每次或者选择上上家(dp[i-2])和这家(nums[i])的和,或者当前这家不抢,抢上一家(dp[i-1]),最优解为 return dp[n-1].
public:
int rob(vector<int>& nums) {
int n = nums.size();
if(n == 0)
return 0;
if(n == 1)
return nums[0];
vector<int> dp(n, 0);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for(int i = 2; i < n; i++) {
int temp = dp[i - 2] + nums[i];
dp[i] = max(temp, dp[i - 1]);
}
return dp[n - 1];
}
};
leetcode 213. House Robber II
Note: This is an extension of House
Robber. After robbing those houses on that street, the thief has found
himself a new place for his thievery so that he will not get too much
attention. This time, all houses at this place are arranged in a
circle. That means the first house is the neighbor of the last one.
Meanwhile, the security system for these houses remain the same as for
those in the previous street. Given a list of non-negative integers
representing the amount of money of each house, determine the maximum
分析:
这题是上一题的升级版,新加了环形的街道(记得不久前做过这一题,只不过改成了牛吃草问题。。)所以就会考虑到,最后一个和第一个房子是不能够同时进入的,要不然会告诉警察叔叔;所以分为两种情况讨论:
0.不包括最后一个屋子—就抢劫0~n-2号屋子;
1.不包括第一个屋子—–就抢劫1~n-1号屋子。
这样的话,return上面两种情况的最大值就好了。调用两次子函数求值,主函数取其最大值返回。
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if(n == 0)
return 0;
if(n == 1)
return nums[0];
if(n == 2)
return max(nums[0], nums[1]);
return max(func(nums, 0, n-2), func(nums, 1, n-1));
}
int func(vector<int>& nums, int begin, int end) {
int n = end - begin + 1;
vector<int> dp(n);
dp[0] = nums[begin];
dp[1] = max(nums[begin], nums[begin+1]);
for(int i = 2; i < n; i++) {
int temp = dp[i - 2] + nums[begin+i];
dp[i] = max(temp, dp[i-1]);
}
return dp[n - 1];
}
};
leetcode 70. 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?
分析:
经典的算法题,我们首先会联想到菲波那切数列,第n(n>=2)个台阶的递推公式为F(n) = F(n-1) + F(n-2),即n的台阶的种数应该是n-1阶的种数与n-2阶种数之和。我们借此分析一下递归的时间和空间复杂度。求解F(n),必须先计算F(n-1)和F(n-2),计算F(n-1)和F(n-2),又必须先计算F(n-3)和F(n-4),以此类推,直至必须先计算F(1)和F(0),然后逆推得到F(n-1)和F(n-2)的结果,算法的时间复杂度随着N的增大呈现指数增长,时间的复杂度为O(2^n),空间复杂度为递归树的深度O(n)。可以看出,中间有很多重复计算,为了避免重复计算带来的时间开销,我们采用动态规划的方法解这道题。
public:
int climbStairs(int n) {
vector<int> dp(n + 1);
dp[0] = 1, dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
};
leetcode 121. Best Time to Buy and Sell Stock
Say you have an array for which the ith element is the price of a given stock on day i. If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.
分析:
我们创建prices数组表示每只股票的当天的价格,minvalue 中保存从0到当前所有股价中最低的价格,ans 中保存minvalue到当前所有股价中能卖掉的最高的价格,然后遍历整个prices数组,更新最低价格和最高价格。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int minvalue = 99999999, ans = 0;
for(int i = 0; i < prices.size(); i++) {
minvalue = min(minvalue, prices[i]);
ans = max(ans, prices[i] - minvalue);
}
return ans;
}
};
leetcode 122. Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price of a given stock on day
i.Design an algorithm to find the maximum profit. You may complete as
many transactions as you like (i.e., buy one and sell one share of the
stock multiple times).Note: You may not engage in multiple transactions at the same time
(i.e., you must sell the stock before you buy again).Example:
Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
分析:
这题与上一题的区别在于买卖次数无线大,由于给定了价格数组,可以做出这样的决策:如果第二天比第一天价格升高,我们就购买。
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size() <= 1) return 0;
int res = 0;
for(int i = 0; i < prices.size() - 1; i++){
if(prices[i] < prices[i+1])
res = res + prices[i+1] - prices[i];
}
return res;
}
};
leetcode 303. Range Sum Query – Immutable
Given an integer array nums, find the sum of the elements between
indices i and j (i ≤ j), inclusive.Example: Given nums = [-2, 0, 3, -5, 2, -1]
sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0, 5) -> -3 Note:
You may assume that the array does not change. There are many calls to
sumRange function.
分析:
根据题意,要多次调用 sumRange 函数。事实上多次调用的时候会重复计算区间内数的和,然而(a,b)区间内数的和可以等于0~b的和 减掉 0~a 的和,所以可以用一个数组v[i]存储入所有0~i的和。
class NumArray {
private:
vector<int> v;
public:
NumArray(vector<int> &nums) {
if(nums.size() == 0)
return ;
v.push_back(nums[0]);
for(int i = 1; i < nums.size(); i++) {
v.push_back(v[i - 1] + nums[i]);
}
}
int sumRange(int i, int j) {
if(i == 0)
return v[j];
return v[j] - v[i - 1];
}
};
// Your NumArray object will be instantiated and called as such:
// NumArray numArray(nums);
// numArray.sumRange(0, 1);
// numArray.sumRange(1, 2);
leetcode 279. Perfect Squares
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …)which sum to n. For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
分析:
创建一个数组dp[i]表示i这个数构成平方和需要数字的最小个数。遍历小于i的平方数,注意如果*j*j=i的时候,dp[i]的值就直接为1。
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1);
dp[1] = 1;
for(int i = 2; i <= n; i++) {
int temp = 99999999;
for(int j = 1; j * j <= i; j++) {
if(j * j == i) {
temp = 1;
break;
}
temp = min(temp, dp[i-j*j] + 1);
}
dp[i] = temp;
}
return dp[n];
}
};
leetcode 53. 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.
分析:
设temp的初始化值为nums[0],i从1一直遍历到len-1,ans始终为temp和ans值中较大的那一个。如果当前temp的值为正数的时候,来者nums[i]加temp,如果当前temp的值为负数的时候, 对于来者nums[i]来说不管怎样nums[i]如果+temp都是在减少nums[i],还不如直接将temp=0舍弃前面的负数和,取nums[i]当作当前的临时总和的值,因此temp的值直接等于nums[i]。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int len = nums.size();
if(len == 0)
return 0;
int ans = nums[0], temp = nums[0];
for(int i = 1; i < len; i++) {
if(temp > 0) {
temp = temp + nums[i];
} else {
temp = nums[i];
}
ans = max(ans, temp);
}
return ans;
}
};