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

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

基础题:字符串的排列

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

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

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

拓展题目:字符串的组合

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

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

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

public static void comb(char[] cs) {
    int len = cs.length;
    int nbits = 1 << len;
    for (int i=0; i<nbits; i++) {   // 列举所有的01情况
        for (int j=0; j<cs.length; j++) {   // 遍历cs,与运算得到是否是1,进行打印
            if ((i & (1 << j)) != 0)
                System.out.print(cs[j]);
        }
        System.out.println("");
    }
}

变形题一:立方体

题目:输入一个含有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;
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值