《剑指offer》面试题28:字符串的排列

本文重点:如果面试题是按照一定要求摆放若干个数字,可以先求出这些数字的所有排列,然后再一一判断每个排列是不是满足题目给定的要求。

基础题:字符串的排列

题目:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出字符a、b、c所排列出来的所有字符串abc、acb、bac、bca、cab和cba。

思路:将一个字符串看成两个部分:第一部分为它的第一个字符,第二部分是后面的字符。

  1. 将所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换。
  2. 固定第一个字符,求后面所有字符的排列。
public void permutation(char[] cs, int index) {
	if (index == cs.length) {
		System.out.println(String.valueOf(cs));
		return ;
	} else {
		for (int loc=index; loc<cs.length; loc++) {
			char tmp = cs[index];
			cs[index] = cs[loc];
			cs[loc] = tmp;
			permutation(cs, index+1);
			cs[loc] = cs[index];
			cs[index] = tmp;
		}
	}
}

拓展题目:字符串的组合

题目:如果不是求字符的所有排列,而是求字符的所有组合。例如a、b、c,则它们的组合是a、b、c、ab、ac、ad、bc、abc。

思路:利用Java的位与运算。

知识点: a = 1 << 2;    // a =4 (0000 0001 -> 0000 0100)

public void comb(char[] cs) {
	int len = cs.length;
	// len = 4
	int nbits = 1 << len;
	// nbits = 16.	即0001 0000
	// i = 0000 0000 到 0000 1111
	for (int i=0; i<nbits; ++i) {
		int t;
		for (int j=0; j<len; j++) {
			// t: 每次左移0位、1位、2位、3位
			// t:0000 0001, 0000 0010, 0000 0100, 0000 1000
			t = 1 << j;	
			System.out.println(j + "--" + t);
			if ((t&i) != 0)		// 位与运算
				System.out.print(cs[j]);
		}
		System.out.println("he");
	}
}

变形题一:立方体

题目:输入一个含有8个数字的数组,判断有没有可能把这8个数字分别放在正方体的8个顶点上(如下图所示)。使得正方体上三组相对的面上的4个顶点的和都相等。

思路:相当于对8个数字进行排列,然后判断有没有某一个的排列符合条件,即a1+a2+a3+a4 = a5+a6+a7+a8,a1+a3+a5+a7=a2+a4+a6+a8,a1+a2+a5+a6=a3+a4+a7+a8。

注意:对数组中的特殊进行排除,比如<=0.


public void cuboid(int[] nums, int index) {
	if (index == nums.length && 
		nums[0]+nums[1]+nums[2]+nums[3] == nums[4]+nums[5]+nums[6]+nums[7]
		&& nums[0]+nums[2]+nums[4]+nums[6] == nums[1]+nums[3]+nums[5]+nums[7]
		&& nums[0]+nums[1]+nums[4]+nums[5] == nums[2]+nums[3]+nums[6]+nums[7]) {
		System.out.println(Arrays.toString(nums));
		return ;
	} else {
		for (int loc=index; loc<nums.length; loc++) { 
			if (nums[loc] <= 0)
				return ;
			int tmp = nums[index];
			nums[index] = nums[loc];
			nums[loc] = tmp;
			cuboid(nums, index+1);
			nums[loc] = nums[index];
			nums[index] = tmp;
		}
	}
}

变形题二:八皇后

题目:8皇后的任意两个不能在同一行,同一列,同一条对角线。

思路:定义一个数组,第i个数字表示位于第i行的皇后的列号。首先全排列,只需要判断每一个排列对应的8个皇后是不是在同一条对角线上,也就是数组的任意两个下标i和j,是不是i - j == ColumnIndex[i] - ColumnIndex[j]或者j - i == ColumnIndex[i] - ColumnIndex[j]。

注释:下面代码可以实现n皇后。

public void queen8(int n) {
	int[] res = new int[n];
	for (int i=0; i<n; i++)
		res[i] = i+1;
	helpQueen8(res, 0);
	System.out.println(ser);
}
public void helpQueen8(int[] nums, int index) {
	if (index == nums.length) {
		// 两个皇后不在同一对角线上
		for (int i=0; i<nums.length; i++) {
			for (int j=i+1; j<nums.length; j++) {
				if (nums[i]-nums[j]==i-j || nums[j]-nums[i]==i-j)
					return ;
			}
		}
		System.out.println(Arrays.toString(nums));
		ser++;
		return ;
	} else {
		for (int loc=index; loc<nums.length; loc++) {
			int tmp = nums[index];
			nums[index] = nums[loc];
			nums[loc] = tmp;
			helpQueen8(nums, index+1);
			nums[loc] = nums[index];
			nums[index] = tmp;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_25024883/article/details/79657992
今日推荐