LeetCode: 267. Palindrome Permutation II

本文介绍了如何通过Java实现从给定字符串生成所有不重复的回文排列。首先检查字符串是否具备形成回文的条件,然后找出一半的回文字符串并识别可能的中间字符,最后生成排列并构造完整回文。示例展示了对于输入aabb和abc的解题过程。

Medium

Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empty list if no palindromic permutation could be form.

Example 1:

Input: "aabb"
Output: ["abba", "baab"]

Example 2:

Input: "abc"
Output: []

解法:

直观的看,如果一个字符串能组成回文,那么它必然可以从中间被切分成两段,且折叠后相应位置上的字符相同。简单地说,就是除了中间的分割点字符(如果字符串长度是奇数的话),左右两段的字符都是成对出现的,也就是说它们的个数是呈偶数出现的。反之,如果给出的字符数组不足以满足上述条件,那么就组成不了回文。

所以这道题我们可以分成三步来解决:

1. 判断给定字符串能否具备组成回文的条件(如果不具备,那么就不用往下算了)

2. 找出组成回文的其中一侧的字符都有哪些,并识别是否存在独立的中间分割字符(如果字符串长度是奇数的话)

3. 基于上一步找到的所有字符生成全排列(就把问题转换成了LeetCode的47题)

4. 将第3步生成的每一组排列的后面加上中间分割字符(如果有的话),然后翻转该组排列并接到后面,即可得到一个符合要求的回文字符串

public static List<String> generatePalindromes(String s) {
		// 1. check possibility
		int[] map = new int[128] ;
		int count = 0;
		for(int i=0; i<s.length(); i++) {
			map[s.charAt(i)] ++ ;
			if(map[s.charAt(i)] % 2 == 0) {
				count -- ;
			} else {
				count ++ ;
			}
		}
		
		if(count > 1) {
			return new ArrayList<>() ;
		}
		
		// 2. generate half palindrome string
		Map<Character, Integer> groups = new HashMap<>() ;
		// 2.1 grouping and find out the single char
		Character single = null ;
		for(int i=0; i<map.length; i++) {
			if(map[i] % 2 == 1) {
				single = (char) i ;
				map[i] -- ;
			}
			
			if(map[i] !=0 ) {
				groups.put((char) i, map[i]/2) ;
			}
			
		}
		// 2.2 generate permutation with grouped string
		return generatePermutation(groups, single) ;
	}

	private static List<String> generatePermutation(Map<Character, Integer> groups, Character single) {
		// calculate max len
		int max = groups.values().stream().reduce(Integer::sum).orElse(0) ;
		List<String> ans = new ArrayList<>() ;
		backtrack(max, new LinkedList<>(), groups, single, ans);
		return ans ;
		
	}

	private static void backtrack(int maxLen, LinkedList<Character> currList, Map<Character, Integer> groups, Character single, List<String> ans) {
		if(currList.size() == maxLen) {
			// generate left half palindrome
			StringBuilder sb = new StringBuilder();    
			
			Iterator<Character> iter = currList.iterator() ;
			while(iter.hasNext()) {
				sb.append(iter.next()) ;
			}
			
			if(single != null) {
				sb.append(single) ;
			}
			
			iter = currList.descendingIterator() ;
			while(iter.hasNext()) {
				sb.append(iter.next()) ;
			}
			
			ans.add(sb.toString()) ;
		}
		
		for(Map.Entry<Character, Integer> entry : groups.entrySet()) {
			char c = entry.getKey() ;
			int count = entry.getValue() ;
			
			if(count == 0) {
				continue ;
			}
			
			currList.addLast(c) ;
			groups.put(c, count - 1) ;
			backtrack(maxLen, currList, groups, single, ans);
			groups.put(c, count) ;
			currList.removeLast() ;
		}
		
	}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yexianyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值