#P3062. 恢复数字序列(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 125
            Accepted: 51
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>暴力枚举          
 
恢复数字序列(100分)
题面描述
给定一个由连续正整数组成的序列,首先将这些数字拼接成一个字符串,然后将字符串中的部分字符打乱顺序。现给定打乱后的字符串和序列的长度,要求还原出原始的连续正整数序列,并输出序列中最小的数字。
思路
- 
理解打乱规则:题目中提到“打乱一部分字符”,但从示例来看,实际上字符串的所有字符都可能被重新排列。因此,可以将其视为字符串的全排列(即字母异位词)。
 - 
还原序列:
- 需要找到一个起始数字 
start,使得从start开始的k个连续正整数拼接成的字符串,与给定的打乱字符串的字符组成相同。 - 由于输入保证唯一解,可以从较小的数字开始尝试,直到找到符合条件的起始数字。
 
 - 需要找到一个起始数字 
 - 
实现步骤:
- 字符计数:统计给定字符串中各个数字字符的出现次数。
 - 枚举起始数字:从 
1开始,依次尝试不同的起始数字。- 对于每个起始数字,拼接 
k个连续的正整数,形成一个新字符串。 - 统计新字符串中各个数字字符的出现次数。
 - 比较新字符串的字符计数与给定字符串的字符计数是否相同。
 - 如果相同,当前起始数字即为所求,输出并结束。
 
 - 对于每个起始数字,拼接 
 - 范围限制:由于字符串长度不超过 
200,且每个数字最多4位(因为数字不超过1000),因此可以将起始数字的范围限定在合理范围内(如1到100000)。 
 - 
优化:
- 使用字符计数数组(长度 
10)来快速比较两个字符串的字符组成。 - 一旦找到符合条件的起始数字,即可停止搜索,因为题目保证唯一解。
 
 - 使用字符计数数组(长度 
 
代码分析
- 
函数
count_digits:接收一个字符串,返回一个长度为10的数组,表示每个数字字符出现的次数。 - 
主函数流程:
- 读取输入字符串 
s和序列长度k。 - 计算输入字符串的字符计数。
 - 从 
1开始,枚举可能的起始数字:- 对于每个起始数字,拼接 
k个连续数字形成字符串。 - 如果拼接后的字符串长度与输入字符串长度不同,跳过当前起始数字。
 - 计算拼接字符串的字符计数,并与输入字符串的字符计数比较。
 - 如果相同,输出当前起始数字并结束程序。
 
 - 对于每个起始数字,拼接 
 - 由于输入保证有唯一解,不需要考虑无解的情况。
 
 - 读取输入字符串 
 
cpp
#include <bits/stdc++.h>
using namespace std;
// 函数:统计字符串中每个数字字符的出现次数
vector<int> count_digits(const string &s) {
    vector<int> cnt(10, 0);
    for(char c : s) {
        if(isdigit(c)) {
            cnt[c - '0']++;
        }
    }
    return cnt;
}
int main(){
    string s;
    int k;
    cin >> s >> k;
    vector<int> target_cnt = count_digits(s);
    // 枚举起始数字,从1开始
    // 由于字符串长度不超过200,每个数字最多4位,因此起始数字不需要超过100000
    for(int start = 1; start <= 100000; start++){
        string concatenated = "";
        for(int i = 0; i < k; i++){
            concatenated += to_string(start + i);
            // 如果拼接后的长度已经超过输入字符串长度,提前停止
            if(concatenated.length() > s.length()) break;
        }
        // 如果长度不匹配,跳过
        if(concatenated.length() != s.length()) continue;
        // 统计拼接字符串的字符数
        vector<int> current_cnt = count_digits(concatenated);
        // 比较字符数是否相同
        if(current_cnt == target_cnt){
            cout << start;
            return 0;
        }
    }
    return 0;
}
python
from collections import Counter
def main():
    import sys
    s, k = sys.stdin.read().split()
    k = int(k)
    target_cnt = Counter(s)
    
    # 枚举起始数字,从1开始
    # 由于字符串长度不超过200,每个数字最多4位,因此起始数字不需要超过100000
    for start in range(1, 100000):
        concatenated = ''.join(str(start + i) for i in range(k))
        if len(concatenated) != len(s):
            continue
        current_cnt = Counter(concatenated)
        if current_cnt == target_cnt:
            print(start)
            return
if __name__ == "__main__":
    main()
java
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
    // 函数:统计字符串中每个数字字符的出现次数
    private static Map<Character, Integer> countDigits(String s) {
        Map<Character, Integer> countMap = new HashMap<>();
        for (char c : s.toCharArray()) {
            countMap.put(c, countMap.getOrDefault(c, 0) + 1);
        }
        return countMap;
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.next();
        int k = scanner.nextInt();
        
        Map<Character, Integer> targetCount = countDigits(s);
        
        // 枚举起始数字,从1开始
        // 由于字符串长度不超过200,每个数字最多4位,因此起始数字不需要超过100000
        for (int start = 1; start <= 100000; start++) {
            StringBuilder concatenated = new StringBuilder();
            for (int i = 0; i < k; i++) {
                concatenated.append(start + i);
            }
            // 如果拼接后的长度与输入字符串长度不同,跳过
            if (concatenated.length() != s.length()) {
                continue;
            }
            Map<Character, Integer> currentCount = countDigits(concatenated.toString());
            // 比较字符数是否相同
            if (currentCount.equals(targetCount)) {
                System.out.println(start);
                return; // 找到后结束程序
            }
        }
    }
}
        题目内容
对于一个连续正整数组成的序列,可以将其拼接成一个字符串,再将字符串里的部分字符打乱顺序。如序列8 9 10 11 12,拼接成的字符串为89101112,打乱一部分字符后得到90811211,原来的正整数10就被拆成了0和1。
现给定一个按如上规则得到的打乱字符的字符串,请将其还原成连续正整数序列,并输出序列中最小的数字。
输入描述
输入一行,为打乱字符的字符串和正整数序列的长度,两者间用空格分隔,字符串长度不超过200,正整数不超过1000,保证输入可以还原成唯一序列。
输出描述
输出一个数字,为序列中最小的数字。
示例1
输入
19801211 5
输出
8