校招算法笔面试 | 校招笔面试真题-数字构造

题目## 题目

题目链接

解题思路

  1. 题目要求构造一个十进制数,使得:
    • 数位和等于给定值 s s s
    • 相邻数位不能相同
    • 不能包含 0 0 0
    • 这个数要尽可能大
  2. 关键发现:
    • 要使数尽可能大,应该使用尽可能大的数字
    • 由于相邻数位不能相同,最优解应该是交替使用两个数字
    • 9和8太大,无法构造出大多数 s s s 值,最优解应该使用1和2交替
  3. 根据 s s s 的值分三种情况:
    • s s s 能被3整除:使用"21"重复
    • s s s 除以3余1:使用"12"重复,最后加"1"
    • s除以3余2:使用"21"重复,最后加"2"

代码

#include <iostream>
#include <string>
using namespace std;

int main() {
    int s;
    cin >> s;
    
    string result;
    if (s % 3 == 0) {
        int pairs = s / 3;
        for (int i = 0; i < pairs; i++) {
            result += "21";
        }
    } else if (s % 3 == 1) {
        int pairs = (s - 1) / 3;
        for (int i = 0; i < pairs; i++) {
            result += "12";
        }
        result += "1";
    } else {  // s % 3 == 2
        int pairs = (s - 2) / 3;
        for (int i = 0; i < pairs; i++) {
            result += "21";
        }
        result += "2";
    }
    
    cout << result << endl;
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int s = sc.nextInt();
        
        StringBuilder result = new StringBuilder();
        if (s % 3 == 0) {
            int pairs = s / 3;
            for (int i = 0; i < pairs; i++) {
                result.append("21");
            }
        } else if (s % 3 == 1) {
            int pairs = (s - 1) / 3;
            for (int i = 0; i < pairs; i++) {
                result.append("12");
            }
            result.append("1");
        } else {  // s % 3 == 2
            int pairs = (s - 2) / 3;
            for (int i = 0; i < pairs; i++) {
                result.append("21");
            }
            result.append("2");
        }
        
        System.out.println(result);
    }
}
s = int(input())

result = ""
if s % 3 == 0:
    pairs = s // 3
    result = "21" * pairs
elif s % 3 == 1:
    pairs = (s - 1) // 3
    result = "12" * pairs + "1"
else:  # s % 3 == 2
    pairs = (s - 2) // 3
    result = "21" * pairs + "2"

print(result)

算法及复杂度

  • 算法:贪心构造
  • 时间复杂度: O ( s ) \mathcal{O}(s) O(s) - 需要构造长度正比于 s s s 的字符串
  • 空间复杂度: O ( s ) \mathcal{O}(s) O(s) - 需要存储构造的结果字符串

题目链接

解题思路

这是一个区间查找问题,需要找到包含所有不同数字的最小区间。具体要求:

  1. 序列中的数字范围在 [ 1 , 2 31 − 1 ] [1, 2^{31}-1] [1,2311]
  2. 找到最小的连续区间,使其包含所有不同的数字
  3. 如果有多个这样的区间,按照出现顺序输出所有区间

解决方案:

  1. 使用双指针(滑动窗口)技术
  2. 对原始数字进行离散化处理,减少空间占用
  3. 使用计数数组记录每个数字的出现次数
  4. 维护最小区间长度和所有符合条件的区间

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 5000010;

int main() {
    int n;
    scanf("%d", &n);
    
    // 离散化处理
    vector<int> a(n + 1);
    map<int, int> mp;
    vector<int> count(n + 1, 0);
    int unique_nums = 0;
    
    for(int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        if(mp.count(x) == 0) {
            mp[x] = unique_nums++;
        }
        a[i] = mp[x];
        count[a[i]]++;
    }
    
    // 寻找最小区间
    vector<pair<int, int>> intervals;
    int min_len = n + 1;
    int l = 1, r = n;
    
    // 初始化右边界
    while(count[a[r]] > 1) {
        count[a[r]]--;
        r--;
    }
    
    while(true) {
        // 调整左边界
        while(count[a[l]] > 1) {
            count[a[l]]--;
            l++;
        }
        
        int curr_len = r - l + 1;
        if(curr_len < min_len) {
            min_len = curr_len;
            intervals.clear();
            intervals.push_back({l, r});
        } else if(curr_len == min_len) {
            intervals.push_back({l, r});
        }
        
        // 移动窗口
        int removed = a[l];
        count[a[l]]--;
        l++;
        
        if(r == n) break;
        while(r < n) {
            r++;
            count[a[r]]++;
            if(a[r] == removed) break;
        }
        if(a[r] != removed) break;
    }
    
    // 输出结果
    printf("%d %d\n", min_len, (int)intervals.size());
    for(int i = 0; i < intervals.size(); i++) {
        if(i > 0) printf(" ");
        printf("[%d,%d]", intervals[i].first, intervals[i].second);
    }
    printf("\n");
    
    return 0;
}
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        
        // 离散化处理
        int[] a = new int[n + 1];
        Map<Integer, Integer> mp = new HashMap<>();
        int[] count = new int[n + 1];
        int uniqueNums = 0;
        
        // 每行读取一个数
        for(int i = 1; i <= n; i++) {
            int x = Integer.parseInt(br.readLine());
            if(!mp.containsKey(x)) {
                mp.put(x, uniqueNums++);
            }
            a[i] = mp.get(x);
            count[a[i]]++;
        }
        
        // 寻找最小区间
        List<int[]> intervals = new ArrayList<>();
        int minLen = n + 1;
        int l = 1, r = n;
        
        // 初始化右边界
        while(count[a[r]] > 1) {
            count[a[r]]--;
            r--;
        }
        
        while(true) {
            // 调整左边界
            while(count[a[l]] > 1) {
                count[a[l]]--;
                l++;
            }
            
            int currLen = r - l + 1;
            if(currLen < minLen) {
                minLen = currLen;
                intervals.clear();
                intervals.add(new int[]{l, r});
            } else if(currLen == minLen) {
                intervals.add(new int[]{l, r});
            }
            
            // 移动窗口
            int removed = a[l];
            count[a[l]]--;
            l++;
            
            if(r == n) break;
            while(r < n) {
                r++;
                count[a[r]]++;
                if(a[r] == removed) break;
            }
            if(a[r] != removed) break;
        }
        
        // 使用StringBuilder加快输出
        StringBuilder sb = new StringBuilder();
        sb.append(minLen).append(" ").append(intervals.size()).append("\n");
        for(int i = 0; i < intervals.size(); i++) {
            if(i > 0) sb.append(" ");
            sb.append("[").append(intervals.get(i)[0]).append(",").append(intervals.get(i)[1]).append("]");
        }
        System.out.println(sb);
    }
}
```python []
import sys
input = sys.stdin.readline
def solve():
    n = int(input())
    
    # 离散化处理
    a = [0] * (n + 1)
    mp = {}
    count = [0] * (n + 1)
    unique_nums = 0
    
    nums = [int(input()) for _ in range(n)]
    for i in range(n):
        x = nums[i]
        if x not in mp:
            mp[x] = unique_nums
            unique_nums += 1
        a[i + 1] = mp[x]
        count[a[i + 1]] += 1
    
    # 寻找最小区间
    intervals = []
    min_len = n + 1
    l, r = 1, n
    
    # 初始化右边界
    while count[a[r]] > 1:
        count[a[r]] -= 1
        r -= 1
    
    while True:
        # 调整左边界
        while count[a[l]] > 1:
            count[a[l]] -= 1
            l += 1
        
        curr_len = r - l + 1
        if curr_len < min_len:
            min_len = curr_len
            intervals = [[l, r]]
        elif curr_len == min_len:
            intervals.append([l, r])
        
        # 移动窗口
        removed = a[l]
        count[a[l]] -= 1
        l += 1
        
        if r == n:
            break
        while r < n:
            r += 1
            count[a[r]] += 1
            if a[r] == removed:
                break
        if a[r] != removed:
            break
    
    # 输出结果
    print(min_len, len(intervals))
    print(' '.join(f'[{interval[0]},{interval[1]}]' for interval in intervals))

solve()

算法及复杂度

  • 算法:双指针(滑动窗口)+ 离散化
  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - 每个位置最多被访问常数次
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要存储离散化映射和计数数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值