Missing number

一、题目

Given a positive integer n(n≤40), pick n-1 numbers randomly from 1 to n and concatenate them in random order as a string s, which means there is a missing number between 1 and n. Can you find the missing number?(Notice that in some cases the answer will not be unique, and in these cases you only need to find one valid answer.)

Examples:
 

  Input: 20
         81971112205101569183132414117
  Output: 16

二、题意

给定正整数n(n≤40),从1到n中随机选择n-1个数,并将它们以随机顺序连接为字符串s,这意味着在1和n之间有一个缺失的数字。你能找到那个缺失的数字吗?(请注意在某些情况下答案不唯一,此时你只需要找到一个有效的答案。)

三、解题思路

分支限界+回溯

归根结底本题时要找到字符串s的合理划分方法,因此可以用回溯法求解。假设字符串s长度为n,则当第i(i<n)个字符要么单独划分为一个数,要么和i+1一起划分为一个数;而第n个字符只能单独划分为一个数。因此可采用回溯法,向下一层左子树搜索的约束条件就是由第i个字符与第i+1个字符结合得到的数字落在1到n的范围内且之前未被划分出来,向下一层右子树搜索的约束条件就是由第i个字符单独形成的数字落在1到n的范围内且之前未被划分出来。如若当前字符为'0',说明之前的划分有误(因为'0'既不能和后一个字符结合,也不能单独成数),应该直接返回上一层。如何知道已经找到了正确的划分呢?只需要在搜索到叶子结点时检验是不是已经划分出n-1个数字即可。

因此划分和回溯就出来了:

1、当前字符下标等于n时,划分结束,判断当前是否找到了n-1个并输出

2、当前字符下标等于n-1时,只有单独划分的情况,递归调用(下标+1)

3、当前字符下标小于n-1时,有两种划分情况:

     1) 单独划分,递归调用(下标+1)

     2) 与后一个一起相组划分,递归调用(下标+2)

#include <iostream>
using namespace std;
int a[41] = {0};   // 记录这些数字有没有被找到 
bool flag = 0;     // 标记找到没,只找一个数 
void find(int findnum, string s, int index, int n){
	int length = s.length();
	if(flag == 1) return;
	if(index == length){
		// 判断有无符合要求的返回
		if(findnum == n-1){
			for(int i=1; i<=n; i++)
				if(a[i] == 0)
					cout<<i<<endl;
			flag = 1;
		}
	}
	if(index == length - 1){   // 最后一个数只能单独成数 
		// 单独成数
		if(a[s[index] - '0'] == 0 && s[index] != '0' && findnum<=n-1 && (s[index]-'0')<=n){
			a[s[index] - '0'] = 1;
			find(findnum+1, s, index+1, n);
			a[s[index] - '0'] = 0;  // 回溯 
		}
	}
	if(index < length - 1){
		// 单独成数
		if(a[s[index] - '0'] == 0 && s[index] != '0' && findnum<=n-1 && (s[index]-'0')<=n){
			a[s[index] - '0'] = 1;
			find(findnum+1, s, index+1, n);
			a[s[index] - '0'] = 0;  // 回溯 
		}
		// 与后一个成数
		if(s[index] != '0' && findnum<=n-1){
			int temp = (s[index] - '0')*10 + (s[index+1]-'0');
			if(temp<= n && a[temp] == 0){
				a[temp] = 1;
				find(findnum+1, s, index+2, n);
				a[temp] = 0;  // 回溯 
			}
		}
	}
}
int main (){
	int n;
	cin>>n;
	string s;
	cin>>s;
	find(0, s, 0, n);
	
	return 0;
} 

参考博文:https://blog.csdn.net/climber16/article/details/81604342

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章