力扣 2024.1.3

总结:摩尔投票,双逆置,写动态规划方程,关键是起始以及终止条件以及迭代方程

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]

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值