题解 | Numeric Keypad

Numeric Keypad

https://www.nowcoder.com/practice/f46db1d185114716abbeaea1d58ffd62

解题思路

这是一个数字构造问题,使用DFS解决:

  1. 预处理可达数字

    • 对于每个位置,预处理可以到达的所有数字
    • 从大到小排序,便于找到最大可行解
  2. DFS策略

    • 从高位到低位逐位构造
    • 使用limit标记是否受到上界限制
    • 当找到第一个可行解时立即返回
  3. 剪枝优化

    • 对于每个位置,只考虑不超过上界的数字
    • 从大到小尝试,保证找到的是最大解

代码

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

class Solution {
private:
    vector<vector<int>> e;
    bool found;
    string result;
    
    void init() {
        e.resize(10);
        // 预处理每个位置可以到达的数字
        e[1] = {9,8,7,6,5,4,3,2,1,0};
        e[2] = {9,8,6,5,3,2,0};
        e[3] = {9,6,3};
        e[4] = {9,8,7,6,5,4,0};
        e[5] = {9,8,6,0};
        e[6] = {9,6};
        e[7] = {9,8,7,0};
        e[8] = {9,8,0};
        e[9] = {9};
        e[0] = {0};
    }
    
    void dfs(int pos, int now, bool limit, string curr, const string& target) {
        if (found) return;
        
        if (pos == -1) {
            found = true;
            result = curr;
            return;
        }
        
        int up = limit ? target[target.length()-pos-1] - '0' : 9;
        
        for (int v : e[now]) {
            if (v > up) continue;
            dfs(pos-1, v, limit && v==up, curr + to_string(v), target);
            if (found) return;
        }
    }
    
public:
    Solution() {
        init();
    }
    
    string findMaxNumber(string k) {
        found = false;
        result = "";
        int n = k.length();
        
        // 从最高位开始尝试
        for (int i = k[0]-'0'; i >= 0; i--) {
            dfs(n-2, i, i == k[0]-'0', to_string(i), k);
            if (found) break;
        }
        
        return result;
    }
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    
    Solution solution;
    while (t--) {
        string k;
        cin >> k;
        cout << solution.findMaxNumber(k) << '\n';
    }
    
    return 0;
}
import java.util.*;

public class Main {
    static class Solution {
        private List<List<Integer>> e;
        private boolean found;
        private String result;
        
        public Solution() {
            init();
        }
        
        private void init() {
            e = new ArrayList<>(10);
            for (int i = 0; i < 10; i++) {
                e.add(new ArrayList<>());
            }
            
            e.get(1).addAll(Arrays.asList(9,8,7,6,5,4,3,2,1,0));
            e.get(2).addAll(Arrays.asList(9,8,6,5,3,2,0));
            e.get(3).addAll(Arrays.asList(9,6,3));
            e.get(4).addAll(Arrays.asList(9,8,7,6,5,4,0));
            e.get(5).addAll(Arrays.asList(9,8,6,0));
            e.get(6).addAll(Arrays.asList(9,6));
            e.get(7).addAll(Arrays.asList(9,8,7,0));
            e.get(8).addAll(Arrays.asList(9,8,0));
            e.get(9).addAll(Arrays.asList(9));
            e.get(0).addAll(Arrays.asList(0));
        }
        
        private void dfs(int pos, int now, boolean limit, String curr, String target) {
            if (found) return;
            
            if (pos == -1) {
                found = true;
                result = curr;
                return;
            }
            
            int up = limit ? target.charAt(target.length()-pos-1) - '0' : 9;
            
            for (int v : e.get(now)) {
                if (v > up) continue;
                dfs(pos-1, v, limit && v==up, curr + v, target);
                if (found) return;
            }
        }
        
        public String findMaxNumber(String k) {
            found = false;
            result = "";
            int n = k.length();
            
            for (int i = k.charAt(0)-'0'; i >= 0; i--) {
                dfs(n-2, i, i == k.charAt(0)-'0', String.valueOf(i), k);
                if (found) break;
            }
            
            return result;
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        
        Solution solution = new Solution();
        while (t-- > 0) {
            String k = sc.next();
            System.out.println(solution.findMaxNumber(k));
        }
    }
}
class Solution:
    def __init__(self):
        self.e = [[] for _ in range(10)]
        self.init_edges()
        self.found = False
        self.result = ""
        
    def init_edges(self):
        self.e[1] = [9,8,7,6,5,4,3,2,1,0]
        self.e[2] = [9,8,6,5,3,2,0]
        self.e[3] = [9,6,3]
        self.e[4] = [9,8,7,6,5,4,0]
        self.e[5] = [9,8,6,0]
        self.e[6] = [9,6]
        self.e[7] = [9,8,7,0]
        self.e[8] = [9,8,0]
        self.e[9] = [9]
        self.e[0] = [0]
    
    def dfs(self, pos: int, now: int, limit: bool, curr: str, target: str):
        if self.found:
            return
            
        if pos == -1:
            self.found = True
            self.result = curr
            return
            
        up = int(target[len(target)-pos-1]) if limit else 9
        
        for v in self.e[now]:
            if v > up:
                continue
            self.dfs(pos-1, v, limit and v==up, curr + str(v), target)
            if self.found:
                return
    
    def find_max_number(self, k: str) -> str:
        self.found = False
        self.result = ""
        n = len(k)
        
        for i in range(int(k[0]), -1, -1):
            self.dfs(n-2, i, i == int(k[0]), str(i), k)
            if self.found:
                break
                
        return self.result

if __name__ == "__main__":
    t = int(input())
    solution = Solution()
    
    for _ in range(t):
        k = input()
        print(solution.find_max_number(k))

算法及复杂度

  • 算法:DFS + 记忆化搜索
  • 时间复杂度:,其中 为数字长度(实际会因剪枝优化大幅降低)
  • 空间复杂度:,递归栈深度
全部评论

相关推荐

不愿透露姓名的神秘牛友
07-09 11:30
找工作7个月,投了7000封,3段世界五百强实习,才有一个offer,牛油们肯定比我强吧
码农索隆:不对不对不对,实习经历这么厉害,简历也没少投,问题出在哪呢
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-11 11:30
点赞 评论 收藏
分享
06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
06-02 15:17
门头沟学院 Java
心爱的idea:怎么会呢 应该是打招呼有问题 问就说实习6个月全国可飞随时到岗
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-11 15:37
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务