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

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