组合算法——华为面试上机题

1、若输入abc、2,则输出ab、ac、bc

2、若输入abcd、3,则输出abc、abd、acd、bcd


实现代码如下:

package com.funny.algorithm;

/**
 * 1、输入abc 2,输出ab、ac、bc
 * 2、输入abcd 3,输出abc、abd、acd、bcd
 */
import java.util.Scanner;

public class Exercise1 {
	public static void main(String[] args) {
		combSelect(0, 1, "abc", 2, "");
	}

	/**
	 * 
	 * @param head
	 *            字母下标起始
	 * @param length
	 *            要截取的是result的第length个字段
	 * @param str
	 *            原有字符串
	 * @param cut
	 *            截取后的字符串应有长度
	 * @param result
	 *            结果
	 */
	private static void combSelect(int head, int length, String str, int cut, String result) {

		// 用s来记录该层初始result值
		String s = result;
		for (int i = head; i < str.length() - (cut - length); i++) {
			// 如果当前所取的第length个字段尚且还少于应当截取的cut长度的字段,则继续递归
			if (length < cut) {
				result += str.substring(i, i + 1);
				combSelect(i + 1, length + 1, str, cut, result);
			}
			// 若当前所取字段为cut长度的最后一个,则叠加后输出
			else if (length == cut) {
				result += str.substring(i, i + 1);
				System.out.println(result);
			}
			//将result回归到循环开始前的值,例如:输出ab后,处于第二层,第二层循环尚未结束,应当以a字母再次叠加c
			result = s;

		}
	}
}


题目分析:

str:原有字符串      cut:截取到的字符串长度     result:截取到的字符串     length:当前截取的是第length个字符


通过两个条件不难看出,这是一个字符串截取的问题,根据给出的整数在原有字符串(str)中截取相应长度(cut)的字符串,并且输出的字符串中字符的排序顺序遵循原字符串中的字符排列顺序,即ab中a的下标为0,b的下标为1,a<b;在abc中a的下标为0,b的下标为1,a<b。

以abc、2为例,首先从abc的第一个字符开始取result的第一个字符,第一个字符取为a,那么第一个字符最多可以取到哪一位呢?总共需要截取cut(2)个字符,当前截取的是第length(1)字符,在str中我应当预留cut-length个字符即预留一个字符,即第一个字符最多取到下标为1的字符,因为下标是从0开始的,所以第一个字符的下标应当小于str.length()-(cut-length),同理可以知道,不论当前取得是第length个字符,都应当在str中预留cut-length个字符,否则最后截取到的字符长度将达不到cut长度,取第一个字母的时候,起始下标为0,因此:

for(int i=0;i<str.length()-cut+length;i++){
      result += str.subString(i,i+1);
}

取到了第一个字符后,再去取第二个字符,应当只能从下标为1的地方开始检索,可以发现跟取第一个字符的原理是一样的,只要保证第二个字符在str中截取的字符的下标不超过str.length()-cut+length即可,此时length应当变为2,同时也可以发现,取第二个字符的时候,在str中的起始检索下标应该是取第一个字符的时候在str中的下标+1,即第一个字符是在str中的下标为0,第二个字符是从1开始检索,这时可以使用递归循环:

combSelect(i+1,length+1,str,cut,result);

既然进入到了递归循环,就代表着要有结束条件,否则会陷入无限死循环,那么什么时候结束呢,不难发现,length代表的是当前所要取第length个字符,而最终长度应为cut,所以当length=cut的时候,即代表这一次取完应当输出结果而不是再进入combSelect了,如果length<cut,则说明还要继续递归下去,result还要继续叠加下去,因此:
                      // 如果当前所取的第length个字段尚且还少于应当截取的cut长度的字段,则继续递归
			if (length < cut) {
				result += str.substring(i, i + 1);
				combSelect(i + 1, length + 1, str, cut, result);
			}
			// 若当前所取字段为cut长度的最后一个,则叠加后输出
			else if (length == cut) {
				result += str.substring(i, i + 1);
				System.out.println(result);
			        }


输出后,应该干嘛呢,比如abc、2,取到第一个字符a,递归,取到第二个字符b,这个时候程序应当在第二个字符的循环当中,条件是i=1;i<3-2+2;i++即i<3;取到b的时候,i=1,那么说明第二个字符还有其他选择,不是仅仅只能是b,那么我们还要继续这个循环,使得i变为2,再次叠加成ac,可是result已经变为了ab,怎么让他变为a呢,因此在循环开始前,定义一个字符串来保存还没有进入for循环时的result值,即

String s = result;

这样在每一次循环之后将result再变为s,则可以再次循环叠加下去。

问题解决。over-(以上均为个人粗浅的理解与解释,若有不同解法和观点欢迎提出指正)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值