简单题三连发!!!
(1) Maximum Subarray
题目很简单,但是非常经典,求最大子序列和问题,很多问题可以转化成这个问题来解决(比如Best Time to Buy and Sell Stock这道题就可以转化成这种问题求解)。根据[1]“根据Wikipedia,这是Brown大学某教授给学生的一道练习题。之后被CMU某教授找到O(n)的解法。”
这个题的解法思路很简单。[2]当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。于是设两个变量,一个是如果以当前元素为最长子数组的最后一个元素,目前所能达到的最大值curSum。另一个是已知的最大值maxSum。需要注意的是遍历完数组如果最后maxSum==0,则表示数组的数里全部都是小于等于0,然后只需要再重新遍历一次数组选出最大的一个数即可。时间复杂度O(n)。
其实是一个动态规划问题。
class Solution {
public:
int maxSubArray(int A[], int n) {
if(n==0)
return 0;
int curSum=0, maxSum=0;
for(int i=0;i<n;i++){
curSum+=A[i];
if(curSum<0)
curSum=0;
if(curSum>maxSum)
maxSum=curSum;
}
if(maxSum==0)
{
maxSum=A[0];
for(int i=0;i<n;i++)
{
if(A[i]>maxSum)
maxSum=A[i];
}
return maxSum;
}
else return maxSum;
}
};
(2) Climbing Stairs
这道题本质是求fibonacci数列。
新手(比如说我)一看到就觉得太简单了,直接一个递归三行代码搞定:
class Solution {
public:
int climbStairs(int n) {
if(n==1) return 1;
if(n==2) return 2;
return climbStairs(n-1)+climbStairs(n-2);
}
};
结果
Time Limit Exceeded
(Last executed input:44)。根据[3],递归程序一般都是太慢了,因为像Fibonacci问题一样,重复计算了很多分支,因此我们用动态规划填表的方法:
class Solution {
public:
int climbStairs(int n) {
int *a=new int[n+1];
a[1]=1;a[2]=2;
for(int i=3;i<=n;i++)
{
a[i]=a[i-1]+a[i-2];
}
return a[n];
}
};
果断秒过
Accepted
(4ms)。然后看了[3],其实用不着一个数组来储存(浪费空间),只用三个变量就可以了:
class Solution {
public:
int climbStairs(int n) {
int a=1,b=2,c=2;
for(int i=3;i<=n;i++)
{
c=a+b;
a=b;
b=c;
}
return n>1 ? c :a;
}
};
小结:这道题虽然简单,但是很经典,而且从第一个没通过的版本到最后只用三个int额外空间的过程体现了对一个问题优化到极致的一种渴望,也提醒自己以后写程序都要注意时间空间的开销问题。
(3) Remove Element
这道题感觉有点简单的无聊了。。。从后往前扫描一遍数组就可以了
class Solution {
public:
int removeElement(int A[], int n, int elem) {
int end=A[n-1],len=n;
for(int i=n-1;i>=0;i--)
{
if(A[i]==elem)
{
A[i]=end;
len--;
end=A[len-1];
}
}
return len;
}
};
参考:
[1] http://blog.csdn.net/magisu/article/details/14515209
[2] http://blog.csdn.net/ithomer/article/details/7096252
[3] http://blog.csdn.net/kenden23/article/details/17377869