剑指offer面试题28 字符串的全排列

有重复全排列解题思路:
整体思路:可以把一个字符串看成两部分组成,第一部分为第一个字符,第二部分是后面的所有字符。这是典型的分治思想,可以用递归实现。

具体来说:第一步首先求所有可能出现在第一个位置上的字符,即把第一个字符和后面的所有的字符(包括第一个字符)进行交换。因字符串中可能有重复的字符,因此在交换前,需要判断从当前字符串的开始位置start到待交换位置end之前,是否有字符和end指向的字符相等,若有,则不进行交换,等到递归到那个字串的时候在进行交换,否则在结果中会出现重复元素。第二步固定第一个字符,求后面所有字符的全排列,过程同上。

import java.util.ArrayList;
import java.util.Collections;

public class Solution {
	
	public static ArrayList<String> Permutation(String str) {
		
		ArrayList<String> arrayList = new ArrayList<>();
		
		if (str == null || str.length() == 0) {
			return arrayList;
		}
		
		char[] charArray = str.toCharArray();
		int start = 0;
		int end = charArray.length - 1;
		arrayList = Permutation(charArray,start,end,arrayList);
		Collections.sort(arrayList);
		return arrayList;
	       
    }
	
	/**
	 * 从start到end-1之间有没有元素和end指向元素相同,若有,则不进行交换,因为在此之前肯定进行了交换
	 */
	private static boolean isSwap(char[] charArray, int start, int end) {
		
		for (int i = start; i < end; i++) {
			if (charArray[i] == charArray[end]) {
				return false;
			}
		}
		return true;
		
	}

	private static ArrayList<String> Permutation(char[] charArray,int start, int end, ArrayList<String> arrayList) {
		
		if (start == charArray.length - 1) {
			//递归地结束条件
			String str = String.valueOf(charArray);
			arrayList.add(str);
			return arrayList;
		}
		
		for (int i = start; i < charArray.length; i++) {
			
			//如果在start到i-1之间,i元素已经出现过,则此时无需交换,因为在此之前已经交换了,避免重复
			if (!isSwap(charArray, start, i)) {
				continue;
			}
			swap(charArray, start, i);
			Permutation(charArray, start + 1, end,arrayList);
			swap(charArray, start, i);
		}
		
		return arrayList;
		
	}

	private static void swap(char[] charArray, int i, int j) {
		
		char temp = charArray[i];
		charArray[i] = charArray[j];
		charArray[j] = temp;
	}
	
	public static void main(String[] args) {
		String s = "abab";
		ArrayList<String> list = Permutation(s);
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
	}
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值