算法与设计分析--实验一

news2024/11/25 9:58:37

蛮力算法的设计与分析(暴力)

这次是某不知名学院开学课程的第一次实验,一共5道题,来自力扣

第一题.216组合总和*力扣题目链接

第一道题是经典的树型回溯

class Solution {
public:
    vector<vector<int>> combinationSum3(int k, int n) {

    }
};

首先我们要知道,力扣上都是核心代码模式,也就是说你只要实现其中的核心部分,一般是一个函数或者结构,不用你从新开始写头文件之类的,比如这里需要你实现的函数就是这个combinationSum3 (计数总和3)。

需要的返回值是一个二维动态数组(c++代码)

右上角可以选择代码模式,这里以C++为例

先看一遍题目描述:

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

所有数字都是正整数。

解集不能包含重复的组合。 

示例 1:

输入: k = 3, n = 7

输出: [[1,2,4]]

示例 2:

输入: k = 3, n = 9

输出: [[1,2,6], [1,3,5], [2,3,4]]

也就是说,我们输出的组合不能重复,顺序无关

这道题就是dfs组合计数的升级版

因为时间效率低,所以题目数据不会很大,数据大了就得换其他方法了

先看一遍递归实现排列型枚举的代码

#include<iostream>

using namespace std;

const int  N= 10;

int path[N], n;

bool st[N];

void dfs(int u)
{
    if(u>n){
        for(int i = 1; i <=n; i++) cout<<path[i]<<' ';
        puts("");
    }else
    {
        for(int i = 1; i<=n;i++){
            if(st[i] == false){
                path[u] = i;
                st[i] = true;
                dfs(u+1);
                st[i] = false;
            }
        }
    }
}
int main(){
    cin>>n;
    dfs(1);
    return 0;
}

我们同理,先存储路径和答案

vector<vector<int>> result; // 存放结果集
    vector<int> path; // 符合条件的结果

确定终止条件

        if (path.size() == k) {
            if (sum == targetSum) result.push_back(path);
            return;
        }

在初学dfs(回溯)时,画一个回溯图会更好理解一点

电脑上画图还是太难了,找一个别人的图

我们可以发现,我们题目要求的K,就是树的深度

每一层都是1~9的选择, 但是我们要注意,因为答案不重复,比如3,6和6,3是属于一个答案

所以我们每一次选择数字都要从该数字的后面开始选择,比如选择了2,下一层选择的数字就是3~9

当然,我们还发现可以剪枝优化,

比如当SUM>我们的target的时候,我们就不用向下遍历了

还有就是当剩下可以选择的数字小于K了,我们也不用向下遍历了

代码+注释如下

class Solution {
private:
    vector<vector<int>> result; // 存放结果集
    vector<int> path; // 符合条件的结果
    void backtracking(int targetSum, int k, int sum, int startIndex) { //最后一个参数为开始选择的数字,防止出现重复组合
        if (sum > targetSum) { // 剪枝操作1
            return; // 如果path.size() == k 但sum != targetSum 直接返回
        }
        if (path.size() == k) { // 终止条件,可以返回了
            if (sum == targetSum) result.push_back(path);
            return;
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) { // 剪枝操作2
            sum += i; // 处理
            path.push_back(i); // 处理
            backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndex
            sum -= i; // 回溯 还原现场
            path.pop_back(); // 回溯 还原现场
        }
    }

public:
    vector<vector<int>> combinationSum3(int k, int n) {
         
        backtracking(n, k, 0, 1);
        return result;

    }
};

第二题.206反转链表力扣题目链接

这道题是基础中的基础了

题目描述:

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL

输出: 5->4->3->2->1->NULL

思路也很简单 就是遍历链表 遍历链表每一个节点的时候把该节点指向前一个节点

当然,为了原链表不被打乱,我们需要一个临时节点

代码+注释如下

class Solution {
    ListNode* reverse(ListNode* pre,ListNode* cur){//参数为 前节点 当前节点
        if(cur == NULL)return pre; //如果是空链表 直接返回 
        auto temp = cur->next; //临时节点指向当前节点的下一节点 为了遍历
        cur->next = pre;//当前节点指向前一节点
        return  reverse(cur,temp); //递归往后遍历
    }
public:
    ListNode* reverseList(ListNode* head) {
      return reverse(NULL,head);//传入头节点
    }
};

第三题:1160.拼写单词力扣题目链接

先看一遍题目描述

给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars。

假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。

注意:每次拼写(指拼写词汇表中的一个单词)时,chars 中的每个字母都只能用一次。

返回词汇表 words 中你掌握的所有单词的 长度之和。

示例 1:

输入:words = ["cat","bt","hat","tree"], chars = "atach"

输出:6

解释:

可以形成字符串 "cat" 和 "hat",所以答案是 3 + 3 = 6。

示例 2:

输入:words = ["hello","world","leetcode"], chars = "welldonehoneyr"

输出:10

解释:

可以形成字符串 "hello" 和 "world",所以答案是 5 + 5 = 10。

提示:

1 <= words.length <= 1000

1 <= words[i].length, chars.length <= 100

所有字符串中都仅包含小写英文字母

class Solution {
public:
    int countCharacters(vector<string>& words, string chars) {

    }
};

题目传入的是一个字符串动态数组,一个目标字符串

这道题出在这样有点怪怪的,一开始用dfs没做出来

用类似哈希的做法就轻松搞定了

原理就是把chars里的每一个字母进行计数,当目标单词中每个字母计数不为0时,则证明能拼出这个单词

代码+注释如下:
 

class Solution {
public:
    int countCharacters(vector<string>& words, string chars) {
        int m[26]; // 计数,类哈希表,保存chars每个字母出现的次数
        memset(m, 0, sizeof(m)); //不是全局变量 得初始化
        for (char ch : chars) {
            m[ch-'a'] ++; //计数
        }
        int ret = 0;
        for (auto word : words) {
            int temp[26];
            memcpy(temp, m, sizeof(m));
            bool canSpell = true;
            for (char ch : word) {
                if (temp[ch-'a'] == 0) {
                    canSpell = false;
                    break;
                }
                temp[ch-'a'] --;
            }
            if (canSpell) {
                ret += word.size();
            }
        }
        return ret;
    }
};

第四题 
1475. 商品折扣后的最终价格

题目描述:

给你一个数组 prices ,其中 prices[i] 是商店里第 i 件商品的价格。

商店里正在进行促销活动,如果你要买第 i 件商品,那么你可以得到与 prices[j] 相等的折扣,其中 j 是满足 j > i 且 prices[j] <= prices[i] 的 最小下标 ,如果没有满足条件的 j ,你将没有任何折扣。

请你返回一个数组,数组中第 i 个元素是折扣后你购买商品 i 最终需要支付的价格。

示例 1:

输入:prices = [8,4,6,2,3]

输出:[4,2,4,2,3]

解释:

商品 0 的价格为 price[0]=8 ,你将得到 prices[1]=4 的折扣,所以最终价格为 8 - 4 = 4 。

商品 1 的价格为 price[1]=4 ,你将得到 prices[3]=2 的折扣,所以最终价格为 4 - 2 = 2 。

商品 2 的价格为 price[2]=6 ,你将得到 prices[3]=2 的折扣,所以最终价格为 6 - 2 = 4 。

商品 3 和 4 都没有折扣。

示例 2:

输入:prices = [1,2,3,4,5]

输出:[1,2,3,4,5]

解释:在这个例子中,所有商品都没有折扣。

示例 3:

输入:prices = [10,1,1,6]

输出:[9,0,1,6]

提示:

1 <= prices.length <= 500

1 <= prices[i] <= 10^3

简单题,我们可以完全按照题目意思写一个二重循环遍历就好

数据也不大,暴力就能过(废话,不能怎么叫暴力算法试验报告)

class Solution {
public:
    vector<int> finalPrices(vector<int>& prices) {
    vector<int> res;  //不改变原数组 开个数组存答案
    bool flag = true; //判断是否加入答案
    for(int i = 0; i < prices.size(); i ++ )
    {
        for(int j = 1; j < prices.size(); j ++ )
        {
            if(j > i && prices[j] <= prices[i]) // 题目给的条件照抄
            {
            res.push_back(prices[i] - prices[j]);
            flag = false;
            break;
            }
            
        }
        if(flag) 
        res.push_back(prices[i]);
        else
        flag = true; 
    }
    return res;
    }
};

看了一下评论,这道题单调栈也能做,时间复杂度能优化到O(n)

class Solution {
public:
    vector<int> finalPrices(vector<int>& prices) {
        //维护一个价格单调递增的栈存储索引值
        //若当前价格小于栈顶所指价格,则栈顶索引值出栈,计算该索引处折扣后的价格,直到栈为空或当前价格大于栈顶所指价格
        //将当前索引入栈
        if(prices.empty()) return {};
        stack<int> s;
        int len=prices.size();
        vector<int> ans(len);
        s.push(0); //将第一个元素的索引入栈
        for(int i=1;i<len;++i)
        {
            while(!s.empty()&&prices[i]<=prices[s.top()])
            {
                ans[s.top()]=prices[s.top()]-prices[i]; //计算折扣后的价格
                s.pop(); //出栈
            }
            s.push(i);
        }
        while(!s.empty()) //剩余的是没有折扣的
        {
            ans[s.top()]=prices[s.top()];
            s.pop();
        }
        return ans;
    }
};

第五题
1518. 换水问题

题目描述:

小区便利店正在促销,用 numExchange 个空酒瓶可以兑换一瓶新酒。你购入了 numBottles 瓶酒。

如果喝掉了酒瓶中的酒,那么酒瓶就会变成空的。

请你计算 最多 能喝到多少瓶酒。

输入:numBottles = 9, numExchange = 3

输出:13

解释:你可以用 3 个空酒瓶兑换 1 瓶酒。

所以最多能喝到 9 + 3 + 1 = 13 瓶酒。

输入:numBottles = 15, numExchange = 4

输出:19

解释:你可以用 4 个空酒瓶兑换 1 瓶酒。

所以最多能喝到 15 + 3 + 1 = 19 瓶酒。

示例 3:

输入:numBottles = 5, numExchange = 5

输出:6

示例 4:

输入:numBottles = 2, numExchange = 3

输出:2

 提示:

1 <= numBottles <= 100

2 <= numExchange <= 100

看着题目很复杂,实际上那是非常非常的简单,之前的题目瓶盖还能换酒,这个只有瓶子能换酒

大一的C语言基础题都比这难

不说了,直接上代码和注释,看完应该都能懂 也不用什么优化了,暴力算法已经超越100%了,这题基数小,暴力最快

class Solution {
public:
    int numWaterBottles(int numBottles, int numExchange) {
        int res = 0; //存答案
        int temp = numBottles;  // 存初始瓶数
        res += numBottles;
        while(temp >= numExchange) //如果剩下的瓶子换不了就结束
        {
            res += temp / numExchange;
            int temp2 = temp % numExchange; // 记得要加上上一轮换不了的余数
            temp /= numExchange;
            temp += temp2;
        }
        return res;
    }
};

总结:

新学期算法课的第一次试验,除了第一题有难度,其他基本是拿来凑数的

第一题是搜索和回溯,也是真正“暴力”算法的样子,其他的更多像一个模拟题,复述题目内容就好

半年了,学校蓝桥杯的报名费都还没报销,真是对自己学算法的同学极大的鼓励啊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/989136.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

红米Note12Turbo解锁BL刷入PixelExperience原生ROM系统详细教程

红米Note12Turbo的兄弟是国外POCO F5 机型&#xff0c;并且该机性价比非常高&#xff0c;国内外销量也还可以&#xff0c;自然不缺第三方ROM适配。目前大家心心念念的原生PixelExperience已成功发布&#xff0c;并且相对来说&#xff0c;适配程度较高&#xff0c;已经达到日用的…

sqlserver union和union all 的区别

1.首先在数据库编辑1-40数字&#xff1b; 2.查询Num<30的数据&#xff0c;查询Num>20 and Num<40的数据&#xff0c;使用union all合并&#xff1b; 发现30-20的数字重复了&#xff0c;可见union all 不去重&#xff1b; 3.查询Num<30的数据&#xff0c;查询Num…

嵌入式Linux驱动开发(同步与互斥专题)(一)

一、内联汇编 1.1、语法 内联汇编实现加法 1.2、同步互斥失败的例子 进程A在读出valid时发现它是1&#xff0c;减1后为0&#xff0c;这时if不成立&#xff1b;但是修改后的值尚未写回内存&#xff1b;假设这时被程序B抢占&#xff0c;程序B读出valid仍为1&#xff0c;减1后为…

Callable、Future和FutureTask

一、Callable 与 Runnable 先说一下java.lang.Runnable吧&#xff0c;它是一个接口&#xff0c;在它里面只声明了一个run()方法&#xff1a; public interface Runnable {public abstract void run(); }由于run()方法返回值为void类型&#xff0c;所以在执行完任务之后无法返…

云数据库知识学习——概述

一、云计算是云数据库兴起的基础 云计算是分布式计算、并行计算、效用计算、网络存储、虚拟化、负载均衡等计算机和网络技术发展融合的产物。云计算是由一系列可以动态升级和被虚拟化的资源组成的&#xff0c;用户无需掌握云计算的技术&#xff0c;只要通过网络就可以访问这些资…

关于近期小程序测试的常见漏洞演示

本章节将为大家介绍一下小程序常见的漏洞的展示案例&#xff0c;包括支付业务逻辑漏洞、任意用户登录漏洞、水平越权漏洞等高危漏洞。 以上小程序测试均获取授权&#xff0c;并且客户均已得到修复(仅供学习&#xff0c;请勿恶意攻击)​ 关于微信小程序如何拦截数据包&#xff…

Nat. Communications Biology2022 | PepNN+: 用于识别多肽结合位点的深度关注模型

论文标题&#xff1a;PepNN: a deep attention model for the identification of peptide binding sites 论文链接&#xff1a;PepNN: a deep attention model for the identification of peptide binding sites | Communications Biology 代码地址&#xff1a;oabdin / PepN…

csp非零段划分

202109-2 非零段划分 计算机软件能力认证考试系统 code&#xff1a; #include<bits/stdc.h> using namespace std; const int N5e59;int a[N];vector<int> v[N];//v[i]存放所有元素值为i的元素的下标 int main() {ios::sync_with_stdio(false);cin.tie(0),cout.…

20230908_python练习_服务端与客户端数据交互

用户可以通过简单操作进行服务端数据交互&#xff0c;通过简单的sql语句直接获取EXCEL表&#xff0c;可以用来作为交互的基础。主要涉及三部分&#xff1a; 1:数据库存储表结构 --日志记录表结构 create table shzc.yytowz_service_title (leixing varchar2(18),ziduan1 v…

C#__多线程之任务和连续任务

/// <summary> /// /// 任务&#xff1a;System.Threading.Tasks&#xff08;异步编程的一种实现方式&#xff09; /// 表应完成某个单元工作。这个工作可以在单独的线程中运行&#xff0c;也可以以同步方式启动一个任务。 /// /// 连续任务&#…

【笔试强训选择题】Day36.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01; 文章目录 前言一、Day…

蚂蚁发布金融大模型:两大应用产品支小宝2.0、支小助将在完成备案后上线

9月8日&#xff0c;在上海举办的外滩大会上&#xff0c;蚂蚁集团正式发布金融大模型。据了解&#xff0c;蚂蚁金融大模型基于蚂蚁自研基础大模型&#xff0c;针对金融产业深度定制&#xff0c;底层算力集群达到万卡规模。该大模型聚焦真实的金融场景需求&#xff0c;在“认知、…

六大排序算法(Java版):从插入排序到快速排序(含图解)

目录 插入排序 (Insertion Sort) 直接插入排序的特性总结&#xff1a; 选择排序 (Selection Sort) 直接选择排序的特性总结 冒泡排序 (Bubble Sort) 冒泡排序的特性总结 堆排序&#xff08;Heap Sort&#xff09; 堆排序的特性总结 希尔排序 (Shell Sort) 希尔排序的…

【Redis】3、Redis主从复制、哨兵、集群

Redis主从复制 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 默认情况下&#xff0c;每台Redis服务器…

SpringMvc 之crud增删改查应用

目录 1.创建项目 2.配置文件 2.1pom.xml文件 2.2 web.xml文件 2.3 spring-context.xml 2.4 spring-mvc.xml 2.5 spring-MyBatis.xml 2.6 jdbc.properties 数据库 2.7 generatorConfig.xml 2.8 日志文件log4j2 3.后台代码 3.1 pageBean.java 3.2切面类 3.3 biz层…

米尔电子|第十六届STM32全国研讨会即将走进11个城市

2023年9月12日至10月27日&#xff0c;以“STM32&#xff0c;不止于芯”为主题的第十六届STM32全国巡回研讨会将走进11个城市。本届研讨会为全天会议&#xff0c;我们将围绕STM32最新产品开展技术演讲和方案演示。 本次STM32全国研讨会&#xff0c;米尔电子将现场展出STM32相关…

Unity——导航系统补充说明

一、导航系统补充说明 1、导航与动画 我们可以通过设置动画状态机的变量&#xff0c;让动画匹配由玩家直接控制的角色的移动。那么自动导航的角色如何与动画系统结合呢&#xff1f; 有两个常用的属性可以获得导航代理当前的状态&#xff1a; 一是agent.velocity&#xff0c;…

GO语言网络编程(并发编程)并发介绍,Goroutine

GO语言网络编程&#xff08;并发编程&#xff09;并发介绍&#xff0c;Goroutine 1、并发介绍 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。 B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更…

Java“牵手”天猫商品详情数据,天猫商品详情API接口,天猫API接口申请指南

天猫平台商品详情接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取天猫商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口&#xff0c;通过…

重排链表(算法时间复杂度O(NlogN))

给定一个单链表 L1​→L2​→⋯→Ln−1​→Ln​&#xff0c;请编写程序将链表重新排列为 Ln​→L1​→Ln−1​→L2​→⋯。例如&#xff1a;给定L为1→2→3→4→5→6&#xff0c;则输出应该为6→1→5→2→4→3。 输入格式&#xff1a; 每个输入包含1个测试用例。每个测试用例…