数据结构---字符串(1)

1. 替换空格(剑指offer-4)

题目:请实现一个函数,把字符串中的每个空格替换成“%20”。例如输入“We are happy.”,则输出“We%20are%20happy.”。

解题思路:

1.我们可以先遍历一次字符串,这样就能统计出字符串中空格的总数,并可以由此计算出替换之后的字符串的总长度。每替换一个空格,长度增加2,因此替换以后字符串的长度等于原来的长度加上2乘以空格数目。我们以字符串"We are happy."为例,"We are happy."这个字符串的长度是14(包括结尾符号'\0'),里面有两个空格,因此替换之后字符串的长度是18。

2.我们从字符串的后面开始复制和替换。首先准备两个指针,P1和P2。P1指向原始字符串的末尾,而P2指向替换之后的字符串的末尾(如图(a)所示)。接下来我们向前移动指针P1,逐个把它指向的字符复制到P2指向的位置,直到碰到第一个空格为止。此时字符串包含如图(b)所示,灰色背景的区域是做了字符拷贝(移动)的区域。碰到第一个空格之后,把P1向前移动1格,在P2之前插入字符串"%20"。由于"%20"的长度为3,同时也要把P2向前移动3格如图(c)所示。
我们接着向前复制,直到碰到第二个空格(如图(d)所示)。和上一次一样,我们再把P1向前移动1格,并把P2向前移动3格插入"%20"(如图(e)所示)。此时P1和P2指向同一位置,表明所有空格都已经替换完毕。


注:图中带有阴影的区域表示被移动的字符。(a)把第一个指针指向字符串的末尾,把第二个指针指向替换之后的字符串的末尾。(b)依次复制字符串的内容,直至第一个指针碰到第一个空格。(c)把第一个空格替换成'%20',把第一个指针向前移动1格,把第二个指针向前移动3格。(d)依次向前复制字符串中的字符,直至碰到空格。(e)替换字符串中的倒数第二个空格,把第一个指针向前移动1格,把第二个指针向前移动3格。

java代码实现:

      public static void main(String[] args) {
		String s = "hello new world!";
		char ss[] = s.toCharArray();
		System.out.println(replaceAllBlank(ss));

	}

	// 将字符串空格转换为%20
	public static char[] replaceAllBlank(char[] s) {

		if (s == null || s.length <= 0) {
			return null;
		}

		int originallength = s.length;
		int numberOfBlank = 0;
		for (int i = 0; i < s.length; i++) {
			if (s[i] == ' ') {
				numberOfBlank++;
			}
		}
		
		int newLength = numberOfBlank * 2 + originallength;
		char[] tempArray = new char[newLength];
		System.arraycopy(s, 0, tempArray, 0, originallength);
		
		int indexofOriginal = originallength - 1;
		int indexofNew = newLength - 1;

		while (indexofOriginal >= 0 && indexofOriginal < indexofNew) {
			if (tempArray[indexofOriginal] == ' ') {
				tempArray[indexofNew--] = '0';
				tempArray[indexofNew--] = '2';
				tempArray[indexofNew--] = '%';
			} else {
				tempArray[indexofNew--] = tempArray[indexofOriginal];
			}
			indexofOriginal--;
		}

		return tempArray;

	}

2.字符串全排列问题(剑指offer-28)

题目:输入一个字符串(要求不存在重复字符),打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。

解析:可以看出三步:
首先,求所有可能出现在第一个位置的字符,
其次,把第一个字符和其后面的字符一一交换。如下图所示,分别把第一个字符a和后面的b、c等字符交换的情形。
接着,固定第一个字符,求后面所有字符的排列。这个时候我们仍把后面的所有字符分成两部分:后面字符的第一个字符,以及这个字符之后的所有字符。然后把第一个字符逐一和它后面的字符交换


	public static void main(String[] args) {

		char buf[] = { 'a', 'b', 'c' ,'d'};
		perm(buf, 0, buf.length - 1);

	}

	public static void perm(char[] buf, int start, int end) {

		// 这个判断用于递归到最后的时候输出相应的字符串
		if (start == end) {
			for (int i = 0; i <= end; i++) {
				System.out.print(buf[i]);
			}
			System.out.println();
		} else {

			for (int i = start; i <= end; i++) {
				char temp = buf[start];
				buf[start] = buf[i];
				buf[i] = temp;
				
				perm(buf, start + 1, end);
				
			    temp = buf[start];
				buf[start] = buf[i];
				buf[i] = temp;

			}
		}
	}

相关题目:

1.输入一字符串(要求可以存在重复字符),打印出该字符串中字符的所有排列。例如:输入"abb",输出结果为abb, bab, bba。

解析:去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。
例如:“abb”,第一个字符a和第二个字符b交换,得到“bab”,此时由于第二个字符和第三个字符相同,所有第一个字符“a”不与第三个字符“b“交换。再考虑,”bab“,第二个字符和第三个字符不同,交换得”bba“,此时结束。生成全部排列。

	public static boolean isSwap(char[] buf, int start, int end) {

		for (int i = start; i < end; i++) {
			if (buf[i] == buf[end])
				return false;
		}
		return true;
	}

	// 有重复全排列
	public static void perm1(char[] buf, int start, int end) {

		// 这个判断用于递归到最后的时候输出相应的字符串
		if (start == end) {
			for (int i = 0; i <= end; i++) {
				System.out.print(buf[i]);
			}
			System.out.println();
		} else {

			for (int i = start; i <= end; i++) {
				if (isSwap(buf,start,i)) {
					char temp = buf[start];
					buf[start] = buf[i];
					buf[i] = temp;

					perm1(buf, start + 1, end);

					temp = buf[start];
					buf[start] = buf[i];
					buf[i] = temp;
				}

			}
		}
	}


2.输入一个字符串(要求不存在重复字符),输出该字符串中字符的所有组合。例如:如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。

例如:对于字符序列“abc”,让其与1-7的二进制相与,每次输出对应二进制为1的那几位,即可输出全部组合。

	public static void main(String[] args) {

		char buf[] = { 'a', 'b', 'c' };
		subset(buf, buf.length);
	}

	
	public static void print_subset(char[] pStr, int length , int s)    
	{    
	    for(int i = 0 ; i < length ; ++i)    
	    {    
	        if( (s & (1<<i))!=0 )         // 判断s的二进制中哪些位为1,即代表取某一位    
	           System.out.print(pStr[i]); 
	    }    
	    System.out.println();  
	}    
	  
	public static void subset(char[] pStr, int length)    
	{    
	    for(int i= 1 ; i < (1<<length) ; ++i)    
	    {    
	        print_subset(pStr,length,i);    
	    }    
	}  

4.八皇后问题

题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。(92种


解析:

行:由于八个皇后的任意两个不能处在同一行,那么这肯定是每一个皇后占据一行。于是我们可以定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。

列:先把ColumnIndex的八个数字分别用0-7初始化,接下来我们要做的事情就是对数组ColumnIndex做全排列。由于我们是用不同的数字初始化数组中的数字,因此任意两个皇后肯定不同列。

对角斜线:我们只需要判断得到的每一个排列对应的八个皇后是不是在同一对角斜线上,也就是数组的两个下标i和j,是不是i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。

	private static int g_number = 0;

	public static void main(String[] args) {
		int arr[]={0,1,2,3,4,5,6,7};
		Permutation(arr,0,7);
	}

	// 8皇后
	public static boolean Check(int ColumnIndex[], int length) {
		int i, j;
		for (i = 0; i < length; ++i) {
			for (j = i + 1; j < length; ++j) {
				if (i - j == ColumnIndex[i] - ColumnIndex[j]
						|| j - i == ColumnIndex[i] - ColumnIndex[j]) // 在正、副对角线上
					return false;
			}
		}
		return true;
	}

	public static void Permutation(int ColumnIndex[], int start, int end) {
		if (start == end) {

			if (Check(ColumnIndex, ColumnIndex.length)) // 检测棋盘当前的状态是否合法
			{
				++g_number;
				System.out.println("第" + g_number + "种:");
				for (int i = 0; i < ColumnIndex.length; i++) {
					System.out.print(ColumnIndex[i] + " ");
				}
				System.out.println();
			}
		} else {
			for (int i = start; i <= end; i++) // 全排列
			{
				int temp = ColumnIndex[start];
				ColumnIndex[start] = ColumnIndex[i];
				ColumnIndex[i] = temp;

				Permutation(ColumnIndex, start + 1, end);

				temp = ColumnIndex[start];
				ColumnIndex[start] = ColumnIndex[i];
				ColumnIndex[i] = temp;
			}
		}
	}



参考来源:

字符串的全排列和组合算法


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值