校招算法笔面试 | 校招笔面试真题-字符覆盖

题目## 题目

题目链接

解题思路

这道题要求在字符串 s s s 上覆盖字符串 t t t 中的字符,得到字典序最大的结果。关键点是:

  1. 可以从 t t t 中选择任意字符覆盖 s s s 中的字符
  2. t t t 中的每个字符只能使用一次
  3. 不一定要用完 t t t 中的所有字符
  4. 需要得到字典序最大的结果

解题步骤:

  1. t t t 中的字符排序(从大到小)
  2. 从左到右遍历 s s s,对于每个位置:
    • 检查 t t t 中所有剩余字符,找到能使结果字典序最大的替换方案
    • 如果找到更好的替换方案,则进行替换
  3. 输出最终结果

例如对于输入:

  • s = “fedcba”
  • t = “ee”

正确的处理过程:

  1. t t t 排序得到 “ee”
  2. 遍历 s s s,在每个位置都尝试所有可能的替换
  3. 最终得到 “feeeba”(在 ‘d’ 和 ‘c’ 的位置用 ‘e’ 替换)

代码

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

int main() {
    string s, t;
    cin >> s >> t;
    
    // 将t中的字符排序(从大到小)
    sort(t.begin(), t.end(), greater<char>());
    
    // 标记t中字符的使用情况
    vector<bool> used(t.length(), false);
    
    // 遍历s中的每个位置
    for(int i = 0; i < s.length(); i++) {
        char maxChar = s[i];
        int maxIndex = -1;
        string temp = s;
        
        // 尝试用t中每个未使用的字符替换当前位置
        for(int j = 0; j < t.length(); j++) {
            if(!used[j]) {
                temp[i] = t[j];
                if(temp > s) {  // 如果得到更大的字符串
                    s = temp;
                    maxIndex = j;
                }
                temp = s;  // 恢复临时字符串
            }
        }
        
        // 如果找到了更好的替换方案
        if(maxIndex != -1) {
            used[maxIndex] = true;
        }
    }
    
    cout << s << endl;
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        String t = sc.next();
        
        // 将t转换为字符数组并排序
        char[] tArr = t.toCharArray();
        Arrays.sort(tArr);
        
        // 标记t中字符的使用情况
        boolean[] used = new boolean[tArr.length];
        char[] sArr = s.toCharArray();
        
        // 遍历s中的每个位置
        for(int i = 0; i < sArr.length; i++) {
            String maxStr = new String(sArr);
            int maxIndex = -1;
            
            // 尝试用t中每个未使用的字符替换当前位置
            for(int j = 0; j < tArr.length; j++) {
                if(!used[j]) {
                    char[] temp = sArr.clone();
                    temp[i] = tArr[j];
                    String newStr = new String(temp);
                    if(newStr.compareTo(maxStr) > 0) {
                        maxStr = newStr;
                        maxIndex = j;
                    }
                }
            }
            
            // 如果找到了更好的替换方案
            if(maxIndex != -1) {
                sArr = maxStr.toCharArray();
                used[maxIndex] = true;
            }
        }
        
        System.out.println(new String(sArr));
    }
}
s = input()
t = input()

# 将s转换为列表以便修改
s = list(s)
# 将t排序(从大到小)
t = sorted(t, reverse=True)
used = [False] * len(t)

# 遍历s中的每个位置
for i in range(len(s)):
    max_str = ''.join(s)
    max_index = -1
    
    # 尝试用t中每个未使用的字符替换当前位置
    for j in range(len(t)):
        if not used[j]:
            temp = s.copy()
            temp[i] = t[j]
            new_str = ''.join(temp)
            if new_str > max_str:
                max_str = new_str
                max_index = j
    
    # 如果找到了更好的替换方案
    if max_index != -1:
        s = list(max_str)
        used[max_index] = True

print(''.join(s))

算法及复杂度

  • 算法:贪心算法。在每个位置都尝试所有可能的替换,选择能得到最大字典序的方案。
  • 时间复杂度: O ( n m ) \mathcal{O}(nm) O(nm),其中 n n n 是字符串 s s s 的长度, m m m 是字符串 t t t 的长度。
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n),需要存储字符串和临时数组。

题目链接

解题思路

这是一道使用Huffman编码思想的问题,主要思路如下:

  1. 问题分析:

    • 给定一个字符串,需要进行二进制编码
    • 相同的字符必须使用相同的编码
    • 要求编码后的总长度最短
  2. 解决方案:

    • 统计每个字符的出现次数
    • 使用优先队列(小顶堆)合并最小的两个长度
    • 类似Huffman树的构建过程
  3. 关键点:

    • 先对字符串排序,便于统计连续相同字符
    • 使用优先队列维护最小的两个长度
    • 每次合并后将新长度加入队列

代码

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

int getMinEncodingLength(string s) {
    // 先排序,便于统计
    sort(s.begin(), s.end());
    
    // 使用小顶堆存储每组相同字符的长度
    priority_queue<int, vector<int>, greater<int>> pq;
    
    // 统计连续相同字符的长度
    for (int i = 0; i < s.length();) {
        int j = i;
        while (j < s.length() && s[j] == s[i]) {
            j++;
        }
        pq.push(j - i);  // 将该字符出现的次数加入队列
        i = j;
    }
    
    // 类似Huffman树的构建过程
    int totalLength = 0;
    while (pq.size() > 1) {
        int a = pq.top(); pq.pop();
        int b = pq.top(); pq.pop();
        totalLength += a + b;  // 合并两个最小的长度
        pq.push(a + b);       // 将合并后的长度放回队列
    }
    
    return totalLength;
}

int main() {
    string s;
    while (cin >> s) {
        cout << getMinEncodingLength(s) << endl;
    }
    return 0;
}
import java.util.*;

public class Main {
    public static int getMinEncodingLength(String s) {
        // 转换为字符数组并排序
        char[] chars = s.toCharArray();
        Arrays.sort(chars);
        
        // 使用优先队列(小顶堆)存储每组相同字符的长度
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        
        // 统计连续相同字符的长度
        for (int i = 0; i < chars.length;) {
            int j = i;
            while (j < chars.length && chars[j] == chars[i]) {
                j++;
            }
            pq.offer(j - i);  // 将该字符出现的次数加入队列
            i = j;
        }
        
        // 类似Huffman树的构建过程
        int totalLength = 0;
        while (pq.size() > 1) {
            int a = pq.poll();
            int b = pq.poll();
            totalLength += a + b;  // 合并两个最小的长度
            pq.offer(a + b);      // 将合并后的长度放回队列
        }
        
        return totalLength;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String s = sc.next();
            System.out.println(getMinEncodingLength(s));
        }
    }
}
from heapq import heappush, heappop

def get_min_encoding_length(s: str) -> int:
    # 先排序,便于统计
    s = sorted(s)
    
    # 使用小顶堆存储每组相同字符的长度
    heap = []
    
    # 统计连续相同字符的长度
    i = 0
    while i < len(s):
        j = i
        while j < len(s) and s[j] == s[i]:
            j += 1
        heappush(heap, j - i)  # 将该字符出现的次数加入堆
        i = j
    
    # 类似Huffman树的构建过程
    total_length = 0
    while len(heap) > 1:
        a = heappop(heap)
        b = heappop(heap)
        total_length += a + b  # 合并两个最小的长度
        heappush(heap, a + b)  # 将合并后的长度放回堆
    
    return total_length

# 处理输入
while True:
    try:
        s = input()
        print(get_min_encoding_length(s))
    except EOFError:
        break

算法及复杂度

  • 算法:贪心(Huffman编码思想)
  • 时间复杂度: O ( n log ⁡ n ) \mathcal{O}(n\log n) O(nlogn) - 排序需要 O ( n log ⁡ n ) \mathcal{O}(n\log n) O(nlogn),堆操作需要 O ( k log ⁡ k ) \mathcal{O}(k\log k) O(klogk) k k k 为不同字符数
  • 空间复杂度: O ( k ) \mathcal{O}(k) O(k) - k k k 为不同字符数,需要优先队列存储
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值