java数据结构与算法之全排列问题

本文详细介绍了如何使用递归算法解决字符串全排列问题,特别是在遇到重复字符时如何通过剪枝操作避免结果集中的重复。给出了具体的Java代码实现,并以LeetCode的第46和47题为例,展示了算法的应用。代码中通过数组记录已访问字符避免重复,确保结果的准确性。
摘要由CSDN通过智能技术生成

①、问题描述

  • 给你一个字符串str,返回这个字符串的全部排列,比如:
    • str = “abc”
    • 返回,[abc , acb, bac, bca,cab,cba]
  • 注意:如果字符串str里有重复字符呢?要求返回的全排列集合里不能存在重复字符串,比如:
    • str = “aa”
    • 返回,[aa]。而不是[aa, aa]

②、解题思路

  • 这种求全排列的问题,最常见也是最容易想到的写法就是【暴力递归】
  • 注意如果str里有重复字符,那么递归时需要做【剪枝】操作来保证结果集里不会有重复字符串
  • 对于递归算法主要是【分析子问题】、【找到递归点】、【确定递归参数(需要几个参数、哪些是变参,哪些是不变参)】、【确定递归退出条件】,算法也比较简单,就直接上代码了

③、相关题目

④、代码

public class PermutationProblem {

    public static void main(String[] args) {
        List<String> list = findPermutation("aba");
        System.out.println(list);
    }

    /**
     * 求string字符串的所有全排列,比如:字符串abc,他的全排列为 abc、acb、bac、bca、cab、cba
     * 比如:
     * 力扣46题:https://leetcode-cn.com/problems/permutations/submissions/
     * 力扣47题:https://leetcode-cn.com/problems/permutations-ii/
     */
    public static List<String> findPermutation(String str) {
      	// 特殊情况特殊处理
        if (str == null || str.length() < 1) {
            return null;
        }
        List<String> resultList = new ArrayList<>();
        process(str.toCharArray(), 0, resultList);
        return resultList;
    }

  	/**
     * @param chars   字符数组
     * @param index   当前来到的位置
     * @param resList 结果集合(将结果收集到这个list里)
     */
    public static void process(char[] chars, int index, List<String> resList) {
        // base case
        if (index == chars.length) {
            // index超过数组最后一个位置时【开始结算】(因为后面已经没有可用选择了)
            resList.add(new String(chars));
            return;
        }
        // 利用缓存来剪枝(由于str只由26个小写字母组成,所以这里开一个长度为26的数组就够表示了),【这里也可以用hashSet来剪枝,原理一样】
        int[] visited = new int[26];
        // i后面的每个位置的字符,都可以来到index位置
        for (int i = index; i < chars.length; i++) {
            int position = chars[i] - 'a';
            // 【之前】有【和i位置的字符】相同的字符被交换到index位置过(那就不用交换,直接看 i + 1位置的数)
            if (visited[position] != 0) {
                continue;
            }
            // 记录上,i位置的字符被交换到index位置过了
            visited[position] = 1;
            // 将i位置和index位置进行交换
            swap(chars, i, index);
            // 处理index + 1后面的位置,看看当index位置是i位置的字符时,后面的位置还有多少种可能(子问题)
            process(chars, index + 1, resList);
            // 每交换完一个位置后,进行第二轮交换时需要将上一轮交换的位置给换回来
            swap(chars, i, index);
        }
    }

    private static void swap(char[] chars, int i, int j) {
        char temp = chars[i];
        chars[i] = chars[j];
        chars[j] = temp;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值