目录
jump-game(贪心,中等)
题目
给出一个非负整数数组,你最初在数组第一个元素的位置
数组中的元素代表你在这个位置可以跳跃的最大长度
判断你是否能到达数组最后一个元素的位置
例如
A =[2,3,1,1,4], 返回 true.
A =[3,2,1,0,4], 返回 false.
思路
所谓贪心算法,就是考虑每一步最优,每一步最优了,那最后结果就都最优解。max表示所有位置中能跳到的最远的距离,max>=i这个条件表示i遍历的每个位置是肯定比所得到的能跳到的最远距离小的。
for(int i=0;i<n&&max>=i;++i)
通过反复的循环,记录下来那个位置可以跳的位置最远,并把这个最远的距离记录下来,和数组长度比较,不比数组长度小的,就是true了。
不需要考虑能不能跳到当前这个位置,肯定能,只需要考虑从当前位置可以跳的最远距离,这也是整个代码的精华所在:
if(i+A[i]>max)max=i+A[i];
最后,需注意的是:max是和n-1比较,而不是n,这是因为循环的时候是从0开始计数的,所以最后一个总长度位置是n-1。
class Solution
{
public:
bool canJump(int A[], int n)
{
int max=0; //max标记能跳到的最远处。
for(int i=0;i<n&&max>=i;++i) //max>=i表示此时能跳到i处,0<=i<n表
if(i+A[i]>max)max=i+A[i]; //示扫描所有能到达的点,在改点处能跳到的最远处。
return max>=n-1?true:false; //如果最后跳的最远的结果大于等于n-1,那么满足
} //能跳到最后。
};
jump-game-ii(贪心,困难)
题目
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
思路
很是巧妙,遍历元素,找到第一个元素的最大步长,存起来为end,并在i到end之间都不在累加步数了,接着进行遍历,遍历每次记录下来当前位置所能到底的最远距离,如果i和end之间的最远距离超过了原来的,那么到i遍历到end的时候,就把这个最远距离给赋值成end,然后继续遍历,这个巧妙就在于,step记录的并不是把当前位置作为起点,当i和end之间有更大的maxi,那么就把end对应成它,那之前记录的在i的step,其实就落到了这个maxi对应的i值了。这样遍历下来,就可以找到最小的步数了。
class Solution {
public:
int jump(int A[], int n) {
int step = 0;
int end = 0;
int maxi = 0;
for (int i = 0; i <= n - 1; i++)
{
maxi = max(i + A[i], maxi);
if (i == end)
{
if (end >= n - 1) {
return step;
}
end = maxi;
step++;
}
}
}
};
maximum-subarray(贪心,简单)
题目
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
思路
思路很简单,逐次遍历,记录下来每次的最大值。这里有一个点睛的地方,就是设置初始的时候是设置的序列的开头第一个元素,而不是粗暴的直接设置为0。另外,对上一次累加结果如果为负就清零,这样保证了求得每次最大值,而且,如果序列真的全为负数,后面的累加也可以起到作用,也可以取到负值的最大值。
class Solution {
public:
int maxSubArray(int A[], int n) {
int sum=A[0],maxsum=A[0];
for(int i=1;i<n;++i)
{
if(sum<0)
sum=0;
sum+=A[i];
maxsum=max(sum,maxsum);
}
return maxsum;
}
};
pascals-triangle(模拟,简单)
题目
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 5 输出: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ]
思路
只要开始循环就可以了,每次循环,先将1给push进去,因为每行的首尾都是1,然后,后面的每个元素,都是上两个加和。
需要注意的是动态二维数组的建立和使用,使用的时候res[i][i],这样的操作。
class Solution {
public:
vector<vector<int> > generate(int numRows) {
vector<vector<int>> res(numRows);
for(int i = 0; i < numRows; ++i){
res[i].push_back(1); //第一个位置为1
for(int j=1; j < i; ++j){
res[i].push_back(res[i-1][j-1] + res[i-1][j]); //j从1开始,那么只有i>=2的时候才会执行这部分
}
if(i > 0) res[i].push_back(1); //最后一个位置也为1,需要注意是不能再第一行中添加
}
return res;
}
};
pascals-triangle-ii(模拟,简单)
给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 3 输出: [1,3,3,1]
进阶:
你可以优化你的算法到 O(k) 空间复杂度吗?
思路
返回的是第K行,杨辉三角的特点就是:
es[j] = temp[j - 1] + temp[j];
这也是它的递推公式, 当然,这个关系得从第三行开始算才行。其中i表示的是每行的行数;j表示的是遍历的两个数相加。
而且,注意每行的首尾都是1。所以j是从1开始计数的,而且,j<i并不等于i。
for (int j = 1; j <i; j++)
点睛之处是,初始值的设法,直接全部设成了1,这样,下面每一步加的时候,虽然res,temp空位都有冗余,但无碍于最后结果。
class Solution {
public:
vector<int > getRow(int numRows) {
vector<int> res(numRows+1, 1);
vector<int> temp(numRows+1, 1);
for (int i = 2; i <= numRows; i++)
{
for (int j = 1; j <i; j++)
{
res[j] = temp[j - 1] + temp[j];
}
temp = res;
}
return res;
}
};