首页 > 其他分享 >Leetcode秋招冲刺(专题10--12)

Leetcode秋招冲刺(专题10--12)

时间:2024-07-01 18:02:54浏览次数:3  
标签:10 12 return nums -- int map 数组 dp

专题10:动态规划

题目509:斐波那契数(NO)

  • 解题思路:动态五部曲

动态五部曲:这里我们用一个一维数组来保存递归的结果

  1. 确定dp数组以及下标的含义
    dp[i]的定义为:第i个数的斐波那契数值是dp[i]

  2. 确定递推公式
    这道题已经把递推公式直接给了:状体转移方程dp[i]=dp[i-1]+dp[i-2];

  3. dp数组如何初始化
    这题题目把如何初始化也直接给了
    dp[0]=0;
    dp[1]=1;

  4. 确定遍历顺序
    从递归公式**dp[i]=dp[i-1]+dp[i-2]**中可以看出,dp[i]是依赖dp[i-1]和dp[i-2],那么遍历顺序一定是从前到后遍历的。

  5. 列举推导dp数组
    按照这个递推公式dp[i]=dp[i-1]+dp[i-2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:0 1 1 2 3 5 8 13 21 34 55
    如果代码写出来发现结果不对,就把dp数组打印出来看看和我们推导的数列是否一致的。

  • 题目

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。

class Solution {
public:
    int fib(int n) {
        if(n<=1)
        {
            return n;
        }
        vector<int>dp(n+1);
        dp[0]=0;
        dp[1]=1;

        //这里实际的个数会是n+1
        for(int i=2;i<=n;i++)
        {
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
};

题目70:爬楼梯(NO)

  • 解题思路:依旧是动规5步曲。
  1. 确定dp数组以及下标的含义

dp[i]:表示爬到第i层楼梯,有dp[i]种方法

这里来推导一下:dp[1]=1,dp[2]=2;dp[3]=3;dp[4]=5;这样递推又会得到和上题一样的答案

  1. 确定递推公式

dp[i]=dp[i-1]+dp[i-2]

  1. dp数组如何初始化

因为dp[0]是没有任何意义的,所以不用对其进行初始化,只需要知道dp[1]=1;dp[2]=2就可以了

  1. 确定遍历顺序

从递推公式dp[i]=dp[i-1]+dp[i-2]可以看出,遍历顺序一定是从前往后遍历的

  1. 列举dp数组

上面列举过了。

class Solution {
public:
    int climbStairs(int n) {
        

        if(n<=1) return n;
        vector<int>dp(n+1);
        dp[1]=1;
        dp[2]=2;
        for(int i=3;i<=n;i++)
        {
            dp[i]=dp[i-1]+dp[i-2];
        }

        return dp[n];

    }
};
  • 疑惑点:为什么可以用dp[i]=dp[i-1]+dp[i-2]作为到达i层的方法数呢

具体解释如下:

  1. 到达第 i 层楼梯的最后一步: 想要到达第 i 层楼梯,最后一步只有两种可能:
  • 从第 i-1 层爬一步。
  • 从第 i-2 层爬两步。
  1. 方法数的累加:
  • 从第 i-1 层爬一步,方法数为 dp[i-1],因为到达第 i-1 层有 dp[i-1] 种方法。
  • 从第 i-2 层爬两步,方法数为 dp[i-2],因为到达第 i-2 层有 dp[i-2] 种方法。
  1. 总方法数: 由于最后一步只有这两种可能,所以到达第 i 层楼梯的总方法数就是这两种情况的方法数之和,即 dp[i] = dp[i-1] + dp[i-2]。

简单来说,dp[i] 就是把所有到达第 i 层楼梯的最后一步可能情况的方法数加起来。

举个例子:

假设我们要爬到第 4 层楼梯。

  • 到达第 4 层的最后一步可以是:
  1. 从第 3 层爬一步,方法数为 dp[3]。
  2. 从第 2 层爬两步,方法数为 dp[2]。
  • 因此,到达第 4 层的总方法数为 dp[4] = dp[3] + dp[2]。

总结:

dp[i] = dp[i-1] + dp[i-2] 这个公式体现了爬楼梯问题的递推关系,它将到达第 i 层楼梯的方法数分解为两种最后一步可能情况的方法数之和,从而简化了问题的求解过程。

题目746:使用最小花费爬楼梯(YES)

  • 解题思路:动规5步曲

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

  1. 确定dp数组的含义
    这里的dp[i]表示到达第i层所需要的最少的花费。

  2. 确定递推公式
    dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);

  3. 如何初始化dp数组
    根据题目就可以知道dp[0]=0 ,dp[1]=0;

  4. 确定遍历的顺序
    这里毫无疑问必然是从前往后,因为dp[i]需要用前面的两个数才能确定。

  5. 列举出dp数组
    这里的本质意义是方便调试,但是这里比较动态,不好推导,不用列举也行。

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
       /*
        这题依旧是动规5步曲:
        1.确定dp数组的含义
        dp[i]表示到达第i层最低的开销

        2.确定递推公式
        dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])

        3.dp数组如何初始化
        dp[0]=0 dp[1]=0; 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
        这句话表示不需要花费

       */
       

        int n=cost.size();
        vector<int>dp(n+1);

        if(n<=1)
        {
            return 0;
        }

        dp[0]=0;
        dp[1]=0;
        for(int i=2;i<=n;i++)
        {
            dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }

        return dp[n];

    }
};

题目392:判断子序列(YES)

  • 解题思路:这题就是要判断s再t中顺序的出现过了,所以只要对t进行一次for只要出现了s的元素s的指针就前进比较下一个。

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int count=0;
        if(s=="")
        {
            return true;
        }else if(t=="")
        {
            return false;
        }
       
        for(int i=0;i<t.size();i++)
        {
            if(s[count]==t[i])
            {
                count++;
            }
            if(count>=s.size())
            {
                return true;
            }
        }
        return false;
    }
};

专题11:贪心算法

题目680:验证回文串||(NO)

  • 解题思路:这题的解题思路是再普通验证回文数的方法上进行叠加的,如果left和right不相等就判断左边去掉一位(left++)或者右边去掉一个(right–)后的字符是否是回文数。这个是回文数的特性。

给你一个字符串 s,最多 可以从中删除一个字符。

请你判断 s 是否能成为回文字符串:如果能,返回 true ;否则,返回 false 。

class Solution {
public:
    //自己封装一个接口用来判断是否是回文字符串
    bool isPalindrome(string s,int left,int right)
    {
        int len=s.size();
        if(len==0) false;
        if(len==1) true;

        while(left<right)
        {
            if(s[left]!=s[right])
            {
                return false;
            }
            left++;
            right--;
        }

        return true;
        
    }

    bool validPalindrome(string s) {
         int left = 0, right = s.size() - 1;
        while (left < right) {
            char c1 = s[left], c2 = s[right];
            if (c1 == c2) {
                ++left;
                --right;
            } else {
                return isPalindrome(s, left, right - 1) || isPalindrome(s, left + 1, right);
            }
        }
        return true;
    }
};

题目860:柠檬水找零(NO)

  • 解题思路:这题一上来想到的就是哈希表,因为能开苏查找是否有钱,当是给5元时,直接收钱就行,当给10元时,需要退5元,当要给20时,退15,而这15有两种分配方法,10+5和5+5+5。分别看这些情况能否满足要求即可。

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

注意,一开始你手头没有任何零钱。

给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        //使用哈希表来存钱
        unordered_map<int,int>map;

        for(int i=0;i<bills.size();i++)
        {
            switch(bills[i])
            {
                case 5:
                //直接收钱
                map[5]++;
                break;
                
                case 10:
                //需要找5元,查找是否有5元
                if(map[5])
                {
                    //有
                    map[5]--;
                    map[10]++;
                }else
                {
                    return false;
                }
                break;

                case 20:
                //需要找15元
                //情况1:10+5
                if(map[10]&&map[5])
                {
                    map[10]--;
                    map[5]--;
                    map[20]++;
                }else if(map[5]>=3)
                {
                    map[5]-=3;
                    map[20]++;
                }else
                {
                    return false;
                }
                break;
            }
        }

        return true;
    }
};

题目942:增减字符串匹配(NO)

  • 解题思路:I就放剩余数字中的最小数,D就放剩余数字中的最大数。(这个其实也不好想)

由范围 [0,n] 内所有整数组成的 n + 1 个整数的排列序列可以表示为长度为 n 的字符串 s ,其中:

如果 perm[i] < perm[i + 1] ,那么 s[i] == ‘I’
如果 perm[i] > perm[i + 1] ,那么 s[i] == ‘D’
给定一个字符串 s ,重构排列 perm 并返回它。如果有多个有效排列perm,则返回其中 任何一个 。

  • 官方题解
class Solution {
public:
    vector<int> diStringMatch(string s) {
        int n = s.length(), lo = 0, hi = n;
        vector<int> perm(n + 1);
        for (int i = 0; i < n; ++i) {
            perm[i] = s[i] == 'I' ? lo++ : hi--;
        }
        perm[n] = lo; // 最后剩下一个数,此时 lo == hi
        return perm;
    }
};

题目1005:K次取反后最大化的数组和(YES)

  • 解题思路:这个k表示又这么多的负号,这些符号应该优先将负数变为正数,后面如果k不为0则拿最小的正数来处理这个k。

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。
重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组 可能的最大和 。

  • myself(这个代码我调试的时候打了一下调试信息)
class Solution {
public:
    //冒泡排序
    void bubble_sort(vector<int>&nums)
    {
        int len=nums.size();
        for(int i=0;i<len-1;i++)
        {
            for(int j=0;j<len-i-1;j++)
            {
                if(nums[j]>nums[j+1])
                {
                    int temp=nums[j];
                    nums[j]=nums[j+1];
                    nums[j+1]=temp;
                }
                
            }
        }
    }
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        //这个k实际就是又多少个负号,
        //先进行排序
        bubble_sort(nums);
        int sum=0;//统计最大值
        int current_min=INT_MAX;//记录正数的最小值
        int current_min_index=0;//记录最小值的下表
        for(int i=0;i<nums.size();i++)
        {
            //这次遍历先处理数据

            //将所有的负数变成正数
            if(nums[i]<0&&k>0)
            {
                nums[i]=abs(nums[i]);
                k--;
            }
            //统计最小值
            if(current_min>nums[i])
            {
                current_min=nums[i];
                current_min_index=i;
            }
        }
        for(int i=0;i<nums.size();i++)
        {
            std::cout<<nums[i]<<" ";
        }
        std::cout<<std::endl;
        std::cout<<"k="<<k<<std::endl;
        std::cout<<"min="<<current_min<<std::endl;


        //上面这次遍历又两种情况
        //一种是k==0那这种就直接加就行
        //另一种是k!=0说明现在nums全部都是正数,则拿一个最小正数来处理这个就行
        int ans=0;
        if(k==0)
        {
            for(int i=0;i<nums.size();i++)
            {
                ans+=nums[i];
            }
        }else
        {
            for(int i=0;i<nums.size();i++)
            {
                if(i==current_min_index)
                {
                    //用这个来处理剩下的k
                    if(k%2==1)
                    {
                        nums[i]=(-nums[i]);
                    }
                }
                ans+=nums[i];
            }
        }
        return ans;
        
    }
};

标签:10,12,return,nums,--,int,map,数组,dp
From: https://blog.csdn.net/qq_71286244/article/details/140071405

相关文章

  • linux使用tftp命令上传文件
    tftp-g-rup.rar192.168.1.249是使用TFTP(TrivialFileTransferProtocol)从指定的服务器(192.168.1.249)下载文件(up.rar)的命令。tftp:是TFTP命令行客户端的命令名称。-g:表示使用TFTP客户端的"get"模式,用于从服务器获取文件。-rup.rar:指定要下载的文件名称为"u......
  • 生产环境部署Nginx服务器双机热备部署-keepalived(多种模式教程)
    前言:今天演示下生产环境keepalived的部署方式,安装模式有很多,比如说主备模型和双主模型,主备分:抢占模式和非抢占模式。这里我会一一展开说具体怎么配置一、双节点均部署Nginx:第一步:上传安装包到/usr/local/第二步:安装编译依赖(使用普通用户需要家sudo)yuminstallgccgcc-c......
  • 【建议收藏】Go语言关键知识点总结
    容器数组和切片在Go语言中,数组和切片是两个基本的数据结构,用于存储和操作一组元素。它们有一些相似之处,但也有许多不同之处。下面我们详细介绍数组和切片的特点、用法以及它们之间的区别。数组数组是固定长度的序列,存储相同类型的元素。数组的长度在定义时就固定下来,不......
  • 周报 | 24.6.24-24.6.30文章汇总
    为了更好地整理文章和发表接下来的文章,以后每周都汇总一份周报。程序员学长|快速学会一个算法,Transformer(下)-CSDN博客周报|24.6.17-24.6.23文章汇总-CSDN博客python|NLTK,一个强大的自然语言处理Python库!_python的nltk库-CSDN博客天才程序员周弈帆|StableDiffus......
  • JavaScript 编程语言【 数据类型】过滤|排序|映射|迭代
    文章目录将border-left-width转换成borderLeftWidth过滤范围原位(inplace)过滤范围降序排列复制和排序数组创建一个可扩展的calculator映射到names映射到对象按年龄对用户排序随机排列数组获取平均年龄数组去重从数组创建键(值)对象Iterableobject(可迭代对象)Symbol.......
  • 新手教学系列——【Python开发】不同系统更换pip源的方法
    在使用Python进行开发时,你可能会发现使用pip安装包的速度较慢,尤其是在国内进行操作时。为了提高安装速度,我们可以将pip的默认源更换为国内的一些镜像源。本文将详细介绍如何在不同操作系统上进行这一操作,并给出常用的国内镜像源。为什么要换源pip默认使用的是官方的Python包......
  • 什么是数据安全?
    网络中的数据安全是一种无价的资产,数据信息在人们的日常生活中无处不在,但同时也面临着前所未有的安全挑战,那什么是数据安全呢?数据安全有着哪些特点呢?数据安全主要就是指保护数据不会受到未经过授权的IP进行访问、使用、泄露或者是进行修改的过程,对于个人用户来说,数据安全关系......
  • 孩子厌学怎么办?13年老教师提醒:4个步骤,让孩子重新爱上学习
    随着学校课程内容越来越多,学生面临的压力也越来越大,孩子也出现了不想上学的情况。而往往学习成绩迟迟上不去只是不想上学的原因之一、感情不顺利、和同学关系处理不好、在学校遭到了孤立等等,都会成为孩子不想上学的原因,不想上学也成了令很多家长头痛的事。很多家长面......
  • 教给孩子这四个学习方法,提高学习效率,效果立现
      “没有孩子是一出生就不爱学习的,如果不爱学习一定是在学习动力、学习方法、学习系统这三个环节上出了问题。”现在给大家介绍世界上已经被证明了的四大超级学习法,和孩子一起进步,交流沟通。  1、费曼学习法  这个学习方法是诺奖获得者费曼提出来,然后由后人总结......
  • 傻熬夜不如巧学习!20个提高学习效率的方法,转给孩子
      要想学习好,方法不能少!好的学习方法是提高学习效率的关键。  学习效率低的原因  1.疲劳式学习,不会自我调整  很多人认为,只要刻苦学习就会收获高分,即使在疲劳的时候也依然要坚持。可是当人疲劳的时候,思路会变得不清晰,再面对大量的知识,就会感觉乏味,甚至失去......