总结:摩尔投票,双逆置,写动态规划方程,关键是起始以及终止条件以及迭代方程
80. 删除有序数组中的重复项 II
中等
956
相关企业
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
int removeDuplicates(int* nums, int numsSize) {
int i=0,j=1,ji=0,n=nums[0],re=1;
for (i=1;i<numsSize;i++){
if(nums[i]==n&&ji==0){
ji++;
nums[j]=nums[i];
j++;
re++;
}
else if(nums[i]!=n){
ji=0;
re++;
nums[j]=nums[i];
j++;
n=nums[i];
}
}
return re;
}
跟删除的如出一辙,只是要加一个计数ji,给他一次重复的机会
169. 多数元素
简单
2.1K
相关企业
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
int majorityElement(int* nums, int numsSize) {
int n=nums[0],i=1,num=1;
for(i=1;i<numsSize;i++){
if(nums[i]==n)
{
num++;
}
if(nums[i]!=n)
{
num--;
if(num==0){
n=nums[i+1];
}
}
}
return n;
}
摩尔投票,没什么好说的,这居然是简单题?
189. 轮转数组
提示
中等
2.1K
相关企业
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
void rotate(int* nums, int numsSize, int k) {
int i=0,n=numsSize-1;
k=(numsSize-k%numsSize-1);
int left=0,right=k,temp=0;
while(left<right){
temp=nums[right];
nums[right]=nums[left];
nums[left]=temp;
left++;
right--;
}
left=k+1;
right=n;
while(left<right){
temp=nums[right];
nums[right]=nums[left];
nums[left]=temp;
left++;
right--;
}
left=0;
right=n;
while(left<right){
temp=nums[right];
nums[right]=nums[left];
nums[left]=temp;
left++;
right--;
}
}
简单的双逆置即可,注意这里的k是向右挪的位数,所以确定左侧逆置范围时要用总长度减去k,注意这里的k>=0,所以可能出现k比size大的情况,即循环移动了多轮,所以要有一个取余的手法
121. 买卖股票的最佳时机
简单
3.3K
相关企业
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
int maxProfit(int* prices, int pricesSize) {
int i = 0, num = 0, temp = 0,a=0;
for (i = 1; i < pricesSize; i++) {
a=prices[i] - prices[i - 1];
temp += a;
if (temp < 0) {
if (num < temp - a) {
num = temp - a;
}
temp = 0;
}
if (num < temp) {
num = temp;
}
}
return num;
}
我的想法就是基于摩尔投票的思想,每次累加差值,如果利润为负,那么一定不是最优解,此时把前一段时间的利润与目前已知的最大利润比较,如果大则替换然后把累加置为0,即重新累加。每次累加后都需要判断一次是否超过目前已知的最大利润。
答案的方法是记录一个最大利润,最低成本,每次都用当前价格减去目前最低成本,如果高于最大利润则更新,如果当前价格低于最低成本也更新。因为利润有时间上的继起关系,所以最低利润只要是当前遍历的元素之前的最低即可。
122. 买卖股票的最佳时机 II
中等
2.4K
相关企业
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
int maxProfit(int* prices, int pricesSize) {
int i = 0, profit = 0, a = 0;
for (i = 1; i < pricesSize; i++) {
a = prices[i] - prices[i - 1];
if (a > 0) {
profit += a;
}
}
return profit;
}
我的想法就是按题目的意思就是我有利润就赚,有亏就撤,那么就直接把所有利润为正的加和即可
答案还提出了一个动态规划的想法,就是每天的状态有两个,一个是持有股票,一个是未持有股票,假设是第 i 天,那么有定义状态 dp[i][0] 表示第 iii 天交易完后手里没有股票的最大利润,dp[i][1] 表示第 iii 天交易完后手里持有一支股票的最大利润
考虑 dp[i][0] 的转移方程,如果这一天交易完后手里没有股票,那么可能的转移状态为前一天已经没有股票,即 dp[i−1][0],或者前一天结束的时候手里持有一支股票,即 dp[i−1][1],这时候我们要将其卖出,并获得 prices[i]的收益。因此为了收益最大化
考虑 dp[i][1] 的转移方程,如果这一天交易完后手里有股票,那么可能的转移状态为前一天没有股票,要让他i天有,只能在i天购买了股票,即 dp[i−1][0]- prices[i],或者前一天结束的时候手里持有一支股票,即 dp[i−1][1]。因此为了收益最大化
接着是起始条件知道第 0 天交易结束的时候 dp[0][0]=0,dp[0][1]=−prices[0]
终止条件是我们只要从前往后依次计算状态即可。由于全部交易结束后,持有股票的收益一定低于不持有股票的收益,因此这时候 dp[n−1][0] 的收益必然是大于 dp[n−1][1]的,最后的答案即为 dp[n−1][0]