暴力递归——打印一个字符串的全部子序列

简介: 暴力递归——打印一个字符串的全部子序列

 

打印一个字符串的全部子序列

我们先来看看字符串的子串和子序列有什么区别?

字符串的子串:必须是连续的一段

字符串的子序列:可以不连续,但是相对次序不能乱(每个字符 要跟不要 所有的路都走一遍)——深度优先遍历

看下图,

image.png

仔细看上边的子序列,是不是就是深度优先遍历呢,哈哈哈。

那么具体如何暴力递归呢,有的时候如果没有思路的话硬写也写不下去,那就只有写一步看一步,如果发现写不下去了,可能是缺少变量啥的,具体分析请看注释。

// str 固定不变的字符串
  // index此时来到的位置 要或者不要,做选择
  // ans 如果index来到了str中的终止位置,把沿途路径所形成的答案放入ans中
  // path 之前做出的选择
  public static void process1(char[] str,int index,List<String> ans,String path) {
    // 如果index来到了字符串的最后一个位置
    // 只需要把沿途路径加入ans,然后返回
    if(index==str.length) {
      ans.add(path);
      return ;
    }
    // 如果没有来到最后一个位置,就要考虑要不要index位置的字符
    // 不要index位置的字符,往下做选择
    String no=path;
    process1(str, index+1, ans, no);
    // 要index位置的字符,往下做选择
    String yes=path+String.valueOf(str[index]);
    process1(str, index+1, ans, yes);
  }
  public static List<String> printAllSubsequences(String s){
    char[] str=s.toCharArray();
    List<String> ans=new LinkedList<>();
    String path="";
    process1(str, 0, ans, path);
    return ans;
  }

现在我们把题目改一下,如果价格条件,要去重,题目变为:

打印一个字符串的全部子序列,要求不要出现重复字面值的子序列

上面举的例子是字符串abc,如果是字符串aaa呢,是不是肯定有字面值重复的子序列。

解决办法:递归方式还是一样,只需要把原先用来装答案的容器改为HashSet就可以,其它都一样,因为集合可以自动去重。主方法调用也需要改一下,返回的时候遍历集合,放入List后再返回结果就可以了。

public static void process2(char[] str,int index,HashSet<String> ans,String path) {
    if(index==str.length) {
      ans.add(path);
      return ;
    }
    String no=path;
    process2(str, index+1, ans, no);
    String yes=path+String.valueOf(str[index]);
    process2(str, index+1, ans, yes);
  }
  public static List<String> printNoRepeat(String s){
    char[] str=s.toCharArray();
    HashSet<String> set=new HashSet<>();
    String path="";
    process2(str, 0, set, path);
    List<String> ans=new ArrayList<>();
    for(String cur:set) {
      ans.add(cur);
    }
    return ans;
  }

如果题目要求不用打印所有字面值不重复的子序列,而是只需要知道所有字面值不重复的子序列的个数,那么这其实是一个经典的动态规划问题,博主后序文章一定会写到的,这篇文章就到这啦,感谢你的三连或者点赞支持🙇‍🙇‍🙇‍

最后附上完整代码:

package com.harrison.class12;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class Code03_PrintAllSubsequences {
  // str 固定不变的字符串
  // index此时来到的位置 要或者不要,做选择
  // ans 如果index来到了str中的终止位置,把沿途路径所形成的答案放入ans中
  // path 之前做出的选择
  public static void process1(char[] str,int index,List<String> ans,String path) {
    // 如果index来到了字符串的最后一个位置
    // 只需要把沿途路径加入ans,然后返回
    if(index==str.length) {
      ans.add(path);
      return ;
    }
    // 如果没有来到最后一个位置,就要考虑要不要index位置的字符
    // 不要index位置的字符,往下做选择
    String no=path;
    process1(str, index+1, ans, no);
    // 要index位置的字符,往下做选择
    String yes=path+String.valueOf(str[index]);
    process1(str, index+1, ans, yes);
  }
  public static List<String> printAllSubsequences(String s){
    char[] str=s.toCharArray();
    List<String> ans=new ArrayList<>();
    String path="";
    process1(str, 0, ans, path);
    return ans;
  }
  public static void process2(char[] str,int index,HashSet<String> ans,String path) {
    if(index==str.length) {
      ans.add(path);
      return ;
    }
    String no=path;
    process2(str, index+1, ans, no);
    String yes=path+String.valueOf(str[index]);
    process2(str, index+1, ans, yes);
  }
  public static List<String> printNoRepeat(String s){
    char[] str=s.toCharArray();
    HashSet<String> set=new HashSet<>();
    String path="";
    process2(str, 0, set, path);
    List<String> ans=new ArrayList<>();
    for(String cur:set) {
      ans.add(cur);
    }
    return ans;
  }
  public static void main(String[] args) {
    String test="accc";
    List<String> ans1=printAllSubsequences(test);
    List<String> ans2=printNoRepeat(test);
    for(String str:ans1) {
      System.out.println(str);
    }
    System.out.println("====================");
    for(String str:ans2) {
      System.out.println(str);
    }
  }
}

image.png

image.png

你学会了吗,🤭嘻嘻


相关文章
|
NoSQL 算法 Linux
秋招无望,五个C++项目助你上岸(可以写进简历)
秋招无望,五个C++项目助你上岸(可以写进简历)
|
4月前
|
机器学习/深度学习 编解码 算法
对三种雷达信号调制类型的识别及MATLAB实现
对三种雷达信号调制类型的识别及MATLAB实现
|
机器学习/深度学习 人工智能 物联网
操作系统的心脏——深入理解内核机制
在本文中,我们揭开操作系统内核的神秘面纱,探索其作为计算机系统核心的重要性。通过详细分析内核的基本功能、类型以及它如何管理硬件资源和软件进程,我们将了解内核是如何成为现代计算不可或缺的基础。此外,我们还会探讨内核设计的挑战和未来趋势,为读者提供一个全面的内核知识框架。
WK
|
机器学习/深度学习 人工智能 算法
那C++适合开发哪些项目
C++ 是一种功能强大、应用广泛的编程语言,适合开发多种类型的项目。它在游戏开发、操作系统、嵌入式系统、科学计算、金融、图形图像处理、数据库管理、网络通信、人工智能、虚拟现实、航空航天等领域都有广泛应用。C++ 以其高性能、内存管理和跨平台兼容性等优势,成为众多开发者的选择。
WK
703 1
|
安全 物联网 Linux
操作系统的心脏——内核
【10月更文挑战第22天】 本文将深入探讨操作系统的核心组成部分——内核,包括其定义、功能、类型以及在现代计算中的重要性。通过了解内核的工作原理和设计哲学,我们可以更好地理解计算机是如何执行任务和管理资源的。
934 2
|
机器学习/深度学习 数据采集 数据可视化
深度学习实践:构建并训练卷积神经网络(CNN)对CIFAR-10数据集进行分类
本文详细介绍如何使用PyTorch构建并训练卷积神经网络(CNN)对CIFAR-10数据集进行图像分类。从数据预处理、模型定义到训练过程及结果可视化,文章全面展示了深度学习项目的全流程。通过实际操作,读者可以深入了解CNN在图像分类任务中的应用,并掌握PyTorch的基本使用方法。希望本文为您的深度学习项目提供有价值的参考与启示。
|
算法 C++
单调栈(C/C++)
单调栈(C/C++)
|
机器学习/深度学习 存储 算法
算法时间复杂度分析
这篇文章讲解了如何分析算法的时间复杂度,包括关注循环执行次数最多的代码段、总复杂度的确定、嵌套代码复杂度的计算方法,并提供了大O阶的推导步骤和常见时间复杂度的列表,同时还介绍了空间复杂度的概念及其重要性。
|
机器学习/深度学习 自然语言处理
Transformer奠基之作《Attention Is All You Need》
Transformer模型,由Google Brain和Google Research在2017年的论文中提出,颠覆了传统NLP依赖RNN和CNN的局面。该模型基于完全的注意力机制,解决了RNN的并行化难题,通过编码器和解码器中的多头自注意力机制捕捉全局依赖。训练策略结合Adam优化器、标签平滑和dropout,使其在机器翻译任务中表现卓越。尽管面临长序列处理的挑战和可能的上下文忽略问题,Transformer仍展示了注意力机制的巨大潜力,对NLP领域产生了深远影响。
688 3
Transformer奠基之作《Attention Is All You Need》