当前位置: 首页 > news >正文

Day16:字符串的排列

某店铺将用于组成套餐的商品记作字符串 goods,其中 goods[i] 表示对应商品。请返回该套餐内所含商品的 全部排列方式 。

返回结果 无顺序要求,但不能含有重复的元素。

示例 1:

输入:goods = "agew"
输出:["aegw","aewg","agew","agwe","aweg","awge","eagw","eawg","egaw","egwa","ewag","ewga","gaew","gawe","geaw","gewa","gwae","gwea","waeg","wage","weag","wega","wgae","wgea"]

LCR 157. 套餐内商品的排列顺序 - 力扣(LeetCode)

很经典的回溯题目

我们回顾一下回溯三部曲:

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

第一次写的时候忘记去掉重复元素了,但是回溯基本上是对的,没有加剪枝:

class Solution {
    public String[] goodsOrder(String goods) {
        if(goods == null){
            return new String[0];
        }

        ArrayList<String> results = new ArrayList<>();
        StringBuilder result = new StringBuilder();

        backtracing(result,goods,results);

        return results.toArray(new String[0]);
    }

    public void backtracing(StringBuilder result, String goods, ArrayList<String> results){
        if(result.length() == goods.length()){
            results.add(result.toString());
            return;
        }

        for(int i = 0; i < goods.length(); i++){
            result = result.append(goods.charAt(i));
            backtracing(result,goods,results);
            result = result.deleteCharAt(result.length() - 1);
        }
    }
}

使用HashSet,并使用used数组记录该元素是否被使用过:

class Solution {
    public String[] goodsOrder(String goods) {
        if(goods == null){
            return new String[0];
        }

        HashSet<String> results = new HashSet<>();
        StringBuilder result = new StringBuilder();
        boolean[] used = new boolean[goods.length()]; // 记录字符是否被使用过

        backtracing(result,goods,results,used);

        return results.toArray(new String[0]);
    }

    public void backtracing(StringBuilder result, String goods, HashSet<String> results,boolean[] used){
        if(result.length() == goods.length()){
            results.add(result.toString());
            return;
        }

        for(int i = 0; i < goods.length(); i++){
            if (used[i]) {
                continue;
            }
            used[i] = true;
            result = result.append(goods.charAt(i));
            backtracing(result,goods,results,used);
            result = result.deleteCharAt(result.length() - 1);
            used[i] = false;
        }
    }
}

其实还有一个问题,像刚才上面的算法,如果是abb这样的字符串,其实是会产生两个abb的,但是我们用HashSet过滤掉了。但是这样会导致算法性能不太好。应该加上这样一个条件判断更合适:

if (i > 0 && goods.charAt(i) == goods.charAt(i - 1) && !used[i - 1]) {
    continue;
}

如果当前字符等于上一个字符并且上一个字符没有被使用过,那么就跳过。

但是好像在力扣里加不加这个算法性能没太大区别。

相关文章:

  • eBPF 实时捕获键盘输入
  • Day2 导论 之 「存储器,IO,微机工作原理」
  • 【测试篇】打破测试认知壁垒,从基础概念起步
  • 零基础上手Python数据分析 (5):Python文件操作 - 轻松读写,数据导入导出不再是难题
  • 【SpringMVC】常用注解:@RequestHeader
  • sentinel限流算法
  • 《DeepSeek深度使用教程:开启智能交互新体验》Deepseek深度使用教程
  • 第五章 树、2叉树
  • 這是我第一次寫關於aapenal服務器管理控制面板的文章
  • “个人陈述“的“十要“和“十不要“
  • 1、操作系统引论
  • Certbot实现SSL免费证书自动续签(CentOS 7 + nginx/apache)
  • (undone) 梳理 xv6-lab-2023 fs.img 生成过程,以及文件系统结构
  • QT编程之QStackedWidget
  • 自定义tiptap插件
  • obsidian中Text Generate的使用教程(以DeepSeek为例)
  • TTS语音模型调用出错
  • 【前端实战】一文掌握响应式布局 - 多设备完美适配方案详解
  • Vuex 高级技巧与最佳实践
  • IMX6ULL学习整理篇——Linux驱动开发的基础3:向新框架迁移
  • 美“群聊泄密门”始作俑者沃尔兹将离职
  • 关于“十五五”,在上海召开的这场座谈会释放最新信号
  • 马克思主义理论研究教学名师系列访谈|杜玉华:马克思主义是“认识世界”和“改变世界”的思维工具
  • 街区党支部书记们亮出治理实招,解锁“善治街区二十法”
  • 国泰海通合并后首份业绩报告出炉:一季度净利润增逾391%
  • “85后”潘欢欢已任河南中豫融资担保有限公司总经理