数据结构学习 jz38 字符串的排列

news2024/9/29 7:19:50

关键词:字典序排列 dfs 回溯 哈希

这种全排列题目可以考虑用下一个排列的方法做,这是最优解(方法四)

题目:套餐内商品的排列顺序

我的:[ 用时: 21 m 11 s ] 回溯 dfs 哈希表

方法一:我写的

回溯 dfs 哈希表

思路:

用dfs套路做。

避免重复结果的方法:

如果goods=aab,那么输出就会有aab aab aba aba baa baa,重复了。

为了避免重复,我在这里的办法是:

        开辟一个哈希表,在存进结果之前先用哈希表检查这个字符串是不是已经在结果里面出现了,如果出现过了,就跳过不存。

        if(count>=goods.size()) //dfs的中止条件,所有都填完了
        {
            auto p=hash.find(temp);//检查得到的单词是否有重复
            if(p==hash.end()) //如果没有重复,则加入res
            {
                hash[temp]=1;
                res.push_back(temp);
            }//如果重复就跳过
            return;
        }

复杂度计算:

时间复杂度O(n!n) 每一个结果都要算一遍

空间复杂度O(n*n+n!)  除了下文提到的,我还有一个哈希表

代码:

class Solution {
//关键:填字母
public:
    vector<string> res;//记录结果
    unordered_map<string,int> hash;//记录某个结果是否已经存在
    vector<string> goodsOrder(string goods) {
        vector<int> vis(goods.size());//记录这个字母的使用状态
        string temp;
        int count=0;//记录填到第几个字母
        dfs(goods,temp,vis,count);//dfs
        return res;
    }
    void dfs(string goods,string& temp,vector<int>& vis,int count)
    {
        if(count>=goods.size()) //dfs的中止条件,所有都填完了
        {
            auto p=hash.find(temp);//检查得到的单词是否有重复
            if(p==hash.end()) //如果没有重复,则加入res
            {
                hash[temp]=1;
                res.push_back(temp);
            }//如果重复就跳过
            return;
        }
        for(int i=0;i<goods.size();++i)//给第count位填字母,从goods里面选
        {
            if(vis[i]==1) continue;//如果这个字母已经被填过,就跳过
            temp.push_back(goods[i]);//读取,填入temp
            vis[i]=1;//记录 已经访问过
            dfs(goods,temp,vis,count+1);//填下一个单词count+1
            vis[i]=0;//回溯 vis
            temp.pop_back();//回溯 temp
        }
        return;
    }
};

方法二:我写的 优化了方法一

回溯 dfs 哈希表

去掉了大的哈希表,减少空间复杂度,优化了时间。

添加了小的哈希表,查询每一位某个字母是否被用过。

思路:

避免重复结果的方法:

如果goods=aab,那么输出就会有aab aab aba aba baa baa,重复了。

为了避免重复,我在这里的办法是:

       每一位都开辟一个哈希表,这个哈希表记录这一位已经填过的字母,比如goods=aab,第一位已经填了第一个a:axx,再次填第一位的时候,查询哈希表,发现第一位已经填过a了,所以这一位就不用再填a了,跳过。

            auto p=vischar.find(goods[i]);//查询这一位是否填过goods[i]
            if(vis[i]==1||p!=vischar.end()) continue;//如果这个字母在这个字符串中被填过或者这个字母在这一位被填过,剪枝
            vischar[goods[i]]=1;//记录 填过这个字母

复杂度计算:

时间复杂度O(n!n) 

空间复杂度O(n*n)  

代码:

class Solution {
public:
    vector<string> res;//记录结果
    vector<string> goodsOrder(string goods) {
        vector<int> vis(goods.size());//记录这个字母的使用状态
        string temp;
        int count=0;//记录填到第几个字母
        dfs(goods,temp,vis,count);//dfs
        return res;
    }
    void dfs(string goods,string& temp,vector<int>& vis,int count)
    {
        if(count>=goods.size()) //dfs的中止条件,所有都填完了
        {
            res.push_back(temp);
            return;
        }
        unordered_map<char,int> vischar;//记录这一位填过的字母
        for(int i=0;i<goods.size();++i)//遍历每一种条件
        {
            auto p=vischar.find(goods[i]);//查询这一位是否填过goods[i]
            if(vis[i]==1||p!=vischar.end()) continue;//如果这个字母在这个字符串中被填过或者这个字母在这一位被填过,剪枝
            vischar[goods[i]]=1;//记录 填过这个字母
            temp.push_back(goods[i]);//载入temp
            vis[i]=1;//记录 这个字符串的这个字母已经访问过
            dfs(goods,temp,vis,count+1);
            vis[i]=0;//回溯 vis
            temp.pop_back();//回溯 temp
        }
        return;
    }
};

方法三:

我写的:回溯 dfs 先快排 利用快排进行查重

依据方法二,可以用快排把小的哈希表优化掉。

思路:

避免重复结果的方法:

如果goods=aab,那么输出就会有aab aab aba aba baa baa,重复了。

为了避免重复,方法三这里的办法是:

       先给goods快排。比如abaa,快排成aaab。

        每次填字母,都按顺序从第一个可以填的字母开始填:查询当前字母goods[i]和上一个字母goods[i-1]是否相同如果相同,并且如果vis[i-1]==0,说明这个字母已经在这一位被填过了,不需要再在这一位填这个字母了,跳过。

必须要有vis[i-1]==0的判断,因为:我们要从第一个可以填的字母开始填

比如:

count=0,填第一位,填第一个a:temp=axxx,此时状态。

vis

1

0

0

0

goods

a

a

a

b

count=1,填第二位,我们想要填第二个a,vis[i-1]==1,不会跳过,成功填上。

vis

1

1

0

0

goods

a

a

a

b

再次回到填第一位的状态:

count=0,填第一位,我们想要填第二个a时,vis[i-1]==0,跳过了。我们只要第一个可以填的,这是第二个,所以不行。

如果没有这个vis[i-1]==0的判断,aaab aab ab都只会输出ab。

if(vis[i]==1||(i>0&&vis[i-1]==0&&goods[i]==goods[i-1])) continue;

复杂度计算:

时间复杂度O(n!n) 快排nlogn

空间复杂度O(n+n) vis->n 递归->n  

代码:

class Solution {
public:
    vector<string> res;
    vector<string> goodsOrder(string goods) {
        sort(goods.begin(),goods.end());
        vector<int> vis(goods.size());
        string temp;
        int count=0;
        dfs(goods,temp,vis,count);
        return res;
    }
    void dfs(string goods,string& temp,vector<int>& vis,int count)
    {
        if(count>=goods.size()) 
        {
            res.push_back(temp);
            return;
        }
        for(int i=0;i<goods.size();++i)
        {
            if(vis[i]==1||(i>0&&vis[i-1]==0&&goods[i]==goods[i-1])) continue;
            temp.push_back(goods[i]);
            vis[i]=1;
            dfs(goods,temp,vis,count+1);
            vis[i]=0;
            temp.pop_back();
        }
        return;
    }
};

 方法四:最优解

用的是下一个排列请看笔记。leetcode31有。

思路:

复杂度计算:

时间复杂度O(n!n) 

空间复杂度O(1)  

代码:

class Solution {
public:
    bool nextPermutation(string& goods) {
        bool stage=false;//如果没有找到goods[i]<goods[i+1],比如654321,则返回false,说明已经找完了
        int i=goods.size()-2;
        while(i>=0&&goods[i]>=goods[i+1])
        {
            --i;
        }
        if(i>=0)
        {
            stage=true;
            int j=goods.size()-1;
            while(j>=0&&goods[i]>=goods[j])
            {
                --j;
            }
            swap(goods[i],goods[j]);
        }
        reverse(goods.begin()+i+1,goods.end());
        return stage;
    }
    vector<string> goodsOrder(string goods) {
        vector<string> res;
        sort(goods.begin(),goods.end());
        res.push_back(goods);
        while(nextPermutation(goods))
        {
            res.push_back(goods);
        }
        return res;
    }
};

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

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

相关文章

Maven 基础安装配置及使用

大家好我是苏麟 , 今天聊聊Maven . Maven Maven , 是Apache公司下基于Java开发的开源项目 . 我们构建一个项目需要用到很多第三方的类库&#xff0c;需要引入大量的jar包。一个项目Jar包的数量之多往往让我们瞠目结舌&#xff0c;并且Jar包之间的关系错综复杂&#xff0c;一…

海外云手机助力企业拓展海外市场

在当前全球化的商业环境中&#xff0c;由于政策限制&#xff0c;许多企业面临着无法顺利将产品推广到国外的困境&#xff0c;使得海外市场的机遇白白流失。而随着科技的不断创新&#xff0c;一种解决企业海外拓展困境的工具应运而生&#xff0c;那就是海外云手机。本文将深入探…

手撕乘积(**Multiplication** **Product**): 穷举和图示(2) 点积的几何意义

手撕乘积(Multiplication & Product): 穷举和图示(2) 点积的几何意义 点乘 x 3 y 5 xNda np.arange(x) >>> array([0, 1, 2]) x2Nda xNda*21 >>> array([1, 3, 5]) yNda np.arange(1, y) >>> array([1, 2, 3, 4]) xyNda np.meshgrid(xN…

Linux系统使用docker部署Geoserver(简单粗暴,复制即用)

1、拉取镜像 docker pull kartoza/geoserver:2.20.32、创建数据挂载目录 # 统一管理Docker容器的数据文件,geoserver mkdir -p /mydata/geoserver# 创建geoserver的挂载数据目录 mkdir -p /mydata/geoserver/data_dir# 创建geoserver的挂载数据目录&#xff0c;存放shp数据 m…

01.15

#include "widget.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();VideoCapture mv;mv.open("D:\\opencv\\heads\\01.mp4");//定义一个存放视频里读取到的一帧图像Mat src;//定义一个存…

配置华为设备NQA UDP Jitter检测VoIP业务抖动

组网需求 如图1所示&#xff0c;总部和子公司之间需要跨越外部网络进行通信&#xff0c;DeviceA和DeviceD为总部和子公司的网络出口设备&#xff0c;DeviceB和DeviceC为外部网络提供商的边缘设备。 总部和子公司之间经常要通过VoIP进行电话会议&#xff0c;要求双向时延小于2…

Java内置锁:深度解析ReentrantReadWriteLock并发类

ReentrantLock和ReentrantReadWriteLock是Java中用于线程同步的重要工具。ReentrantLock提供独占访问&#xff0c;适合需要保护共享资源不被并发修改的场景&#xff0c;同时支持可重入性&#xff0c;适用于递归操作。而ReentrantReadWriteLock则通过读写分离&#xff0c;允许多…

XTuner 微调 课程学习

大语言模型于海量的文本内容上&#xff0c;以无监督和半监督的方式进行训练的 模型微调的目的&#xff1a;使其在具体的使用场景或领域中输出更好的回答 增量预训练——给模型喂新的领域知识&#xff1b; 指令跟随或指令微调—— 基于海量的预训练数据训练出来的模型通常叫做…

[易语言]易语言部署yolox的onnx模型

【官方框架地址】 https://github.com/Megvii-BaseDetection/YOLOX 【算法介绍】 YOLOX是YOLO系列目标检测算法的进一步演变和优化。它由Megvii Technology的研究团队开发&#xff0c;是一个高性能、可扩展的对象检测器。YOLOX在保留快速处理速度的同时&#xff0c;通过引入一…

行业追踪,2024-01-15,含行业对应的etf

自动复盘 2024-01-15 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

Axure RP软件揭秘:设计师的秘密武器

Axure rp是一种快速原型设计工具&#xff0c;可以制作高度互动的HTML原型。设计师不仅可以使用Axure绘制线框图和原型&#xff0c;还可以在Axure rp中完成一系列用户体验设计。在本文中&#xff0c;我们将根据用户体验设计师的真实经验&#xff0c;触发用户体验设计师的实际工作…

Linux之引导和服务篇

系统引导是操作系统运行的开始&#xff0c;在用户能够正常登录之前&#xff0c;Linux的引导过程完成了一系列的初始化任务&#xff0c;并加载必要的程序和命令终端&#xff0c;为用户登录做好准备。 一. 引导过程 开机自检--->MBR引导--->GRUB菜单--->加载Linux内核-…

如何分析测试任务及需求(附分析流程)

测试分析 确认测试范围 根据测试项目的不同需求&#xff0c;有大致几类测试项目类型&#xff1a;商户/平台功能测试、支付方式接入测试、架构调整类测试、后台优化测试、性能测试、基本功能自动化测试。 测试项目需要按照文档要求进行测试需求分析&#xff0c;并给出对应的输出…

Spring MVC文件上传及全局异常处理器

添加依赖 <!--文件上传--> <dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version> </dependency>配置文件上传解析器 <!--配置文件上传解析器-…

一个黑盒测试和白盒测试区别的软件测试面试题

软件测试是确保软件质量的重要环节&#xff0c;而在软件测试中&#xff0c;黑盒测试和白盒测试是两种常见的测试方法。跟小一起学习黑盒测试和白盒测试区别&#xff1a; 它们在测试的角度和目标上存在显著区别&#xff0c;本文将深入探讨这两种测试方法的定义、特点、应用场景…

windows平台高dpi介绍

flutter在windows平台如何自定义dpi设置 系统层级的支持(windows平台对高dpi的支持) 主要有两点&#xff1a; 设置系统的缩放比例 (系统及系统自带的app会根据这个设置来进行缩放&#xff1b;自己的app需要结合自己设置的dpi awareness来实现对应的dpi支持)设置进程的dpi aw…

如何利用小程序改变人力资源行业

随着移动互联网的普及和发展&#xff0c;小程序已经成为了人们生活中必不可少的一部分。小程序不仅提供了便捷的服务&#xff0c;还为各行各业提供了创新和发展的空间。在人力资源行业&#xff0c;利用小程序可以为企业和求职者提供更加高效和便捷的招聘和求职服务。下面&#…

第06章_面向对象编程(基础)拓展练习(求三角形面积,猴子吃桃,圆类,学生类,矩形类)

文章目录 第06章_面向对象编程&#xff08;基础&#xff09;拓展练习1、圆类2、学生类3、MyInt类4、MyDate日期类-15、MyDate日期类-26、数学计算工具类7、常识工具类8、学生对象数组9、员工管理类-110、员工管理类-211、比较大小12、数组排序和遍历13、求三角形面积14、图形工…

vue 使用mock模拟数据

vue 使用mock模拟数据 安装依赖 cnpm install axios --save cnpm install mockjs --save-dev cnpm install json5 --save-dev在根目录下&#xff0c;新建一个mock文件&#xff0c;且创建如下文件 utils.js index.js const Mock require(mockjs) const { param2Obj } …

C++ 数组分页,经常有用到分页,索性做一个简单封装 已解决

在项目设计中&#xff0c; 有鼠标滑动需求&#xff0c;但是只能说能力有限&#xff0c;索性使用 php版本的数组分页&#xff0c;解决问题。 经常有用到分页&#xff0c;索性做一个简单封装、 测试用例 QTime curtime QTime::currentTime();nHour curtime.hour();nMin curtim…