首页 > 试题广场 >

Numeric Keypad

[编程题]Numeric Keypad
  • 热度指数:7833 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
The numberic keypad on your mobile phone looks like below:
123
456
789
0
suppose you are holding your mobile phone with single hand. Your thumb points at digit 1. Each time you can 1)press the digit your thumb pointing at.2)moveyour thumb right,3)move your thumb down. Moving your thumb left or up is not allowed.
By using the numeric keypad under above constrains, you can produce some numbers like 177 or 480 while producing other numbers like 590 or 52 is impossible.
Given a number K, find out the maximum number less than or equal to K that can be produced.

输入描述:
the first line contains an integer T, the number of testcases.
Each testcase occupies a single line with an integer K.

For 50%of the data ,1<=K<=999.
For 100% of the data, 1<=K<=10^500,t<=20.


输出描述:
for each testcase output one line, the maximum number less than or equal to the corresponding K that can be produced.
示例1

输入

3
25
83
131

输出

25
80
129

类似数位dp的做法,先预处理出每一位数字可达的所有数字,然后从大到小从高位向地位枚举

#include<bits/stdc++.h>
using namespace std;
using ll = int64_t;
using pii = pair<int,int>;
vector<vector<int>> e(10),b;
inline void init(){
    e[1] = (vector<int>({9,8,7,6,5,4,3,2,1,0}));
    e[2] = (vector<int>({9,8,6,5,3,2,0}));
    e[3] = (vector<int>({9,6,3}));
    e[4] = (vector<int>({9,8,7,6,5,4,0}));
    e[5] = (vector<int>({9,8,6,0}));
    e[6] = (vector<int>({9,6}));
    e[7] = (vector<int>({9,8,7,0}));
    e[8] = (vector<int>({9,8,0}));
    e[9] = (vector<int>({9}));
    e[0] = (vector<int>({0}));
}

void solve(){

    string s;
    cin>>s;
    int n = s.size();
    bool f = false;
    string res;
    auto dfs = [&](auto &&self, int pos, int now, bool limit, string tp) -> void{
        if(pos==-1){
            f = true;
            res = tp;
            return;
        }
        int up = limit ? s[n-pos-1]-'0' : 9;
        for(auto v:e[now]){
            if(v>up) continue;
            self(self, pos-1, v, limit&&v==up, tp+to_string(v));
            if(f) return;
        }
        return;
    };
    for(int i=s[0]-'0';i>=0;--i){
        dfs(dfs, n-2, i, i==s[0]-'0', to_string(i));
        // cout<<f<<"\n";
        if(f) break;
    }
    cout<<res<<'\n';
}

int main(){

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int _ = 1;
    cin>>_;
    while(_--){
        init();
        solve();

    }

    return 0;
}
发表于 2022-05-23 18:19:46 回复(0)
python实现
代码排在第一
编辑于 2018-09-28 15:23:12 回复(0)
#include <bits/stdc++.h>

using namespace std;

void locate(int d,int &x,int &y)
{     d = d?--d:10;     x = d/3;     y = d%3;
}

bool reach(int x,int y) 
{     int x1,y1,x2,y2;     locate(x-'0',x1,y1);     locate(y-'0',x2,y2);     return x1<=x2 && y1<=y2;     }


int main()
{     int T;     cin>>T;     while(T--)     {         string k;         cin>>k;         for(int i=0;i<k.size()-1;i++)         {             while(!reach(k[i],k[i+1]))             {                 if(--k[i+1]<0)                     k[i--]--;                 for(int j=i+2;j<k.size();j++)                     k[j] = '9';             }         }         cout<<k<<endl;     }     return 0;
}

发表于 2017-12-02 11:20:58 回复(0)
import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        HashMap<Integer, Integer[]> map = getMap();
        s.nextInt();
        while (s.hasNext()) {
            Integer[] ints = parseString(s.next());
            Stack<Integer> l = new Stack<>();
            constructString(ints, 0, map, l, false);

            StringBuilder sb = new StringBuilder();
            for (Integer c : l) {
                sb.append(c);
            }
            System.out.println(sb);
        }
    }

    private static boolean constructString(Integer[] s, int i, HashMap<Integer, Integer[]> map, Stack<Integer> l, boolean flag) {
        if (l.size() == 0) {
            l.push(s[i]);
            if (constructString(s, i + 1, map, l, false)) {
                return true;
            }
            l.set(0, l.peek() - 1);
            return constructString(s, i + 1, map, l, true);
        }
        if (i == s.length)
            return true;
        if (flag) {
            Integer[] q = map.get(l.peek());
            l.push(q[q.length - 1]);
            return constructString(s, i + 1, map, l, flag);
        }

        Integer j = 0, B[] = map.get(l.peek());
        for (; j < B.length; j++) {
            if (B[j] > s[i])
                break;
        }
        for (j--; j > -1; j--) {
            l.push(B[j]);
            if (B[j] < s[i])
                flag = true;
            if (constructString(s, i + 1, map, l, flag))
                return true;
            l.pop();
        }
        return false;
    }

    public static Integer[] parseString(String s) {
        Integer[] ints = new Integer[s.length()];
        for (int i = 0; i < s.length(); i++) {
            ints[i] = s.charAt(i) - 48;
        }
        return ints;
    }

    public static HashMap<Integer, Integer[]> getMap() {
        Integer A[][] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
        HashMap<Integer, Integer[]> map = new HashMap<>();
        LinkedList<Integer> l = new LinkedList<>();
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                for (int x = i; x < 3; x++) {
                    for (int y = j; y < 3; y++) {
                        l.add(A[x][y]);
                    }
                }
                if (j <= 1) {
                    l.addFirst(0);
                }
                map.put(A[i][j], l.toArray(new Integer[0]));
                l.clear();
            }
        }
        map.put(0, new Integer[]{0});
        return map;
    }
}

编辑于 2017-04-25 21:04:53 回复(0)
package com.neil.java;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import org.junit.Test;


public class PhoneNum {
	// 按照下面的排序,返回数组的位置
	/**
	 * 1 2 3 
	 * 4 5 6 
	 * 7 8 9 
	 *   0
	 * 
	 * @param digit
	 * @return
	 */
	static Point locate(int digit) {
		int x = 0, y = 0;
		digit = digit > 0 ? --digit : 10;// 如果是0,则认为其所在的位置是10,其他的都是数字-1,
		x = digit / 3; // 行数
		y = digit % 3; // 列数
		return new Point(x, y);
	}
	/**
	 * 将字符串变成int数组
	 * @param numString 字符串
	 * @return 返回int数组
	 */
	public static int[] stringToIntArray(String numString)
	{
		int [] ret = new int[numString.length()];
		for (int i = 0; i < numString.toCharArray().length; i++) {
			ret[i] = Integer.parseInt(numString.toCharArray()[i]+"");
		}
		return ret;
	}
	
	/**
	 * 将int数组编程字符串输出
	 * @param numArray int数组
	 * @return 返回字符串
	 */
	public static String intArrayToString(int [] numArray)
	{
		StringBuilder ret = new StringBuilder();
		for (int i = 0; i < numArray.length; i++) {
			ret.append(numArray[i]);
		}
		return ret.toString();
	}
	
	/**
	 * 根据题意,我们只能向右,向下走。 因此,第一个数字在键盘矩阵中的位置坐标(x1,y1),第二个数字在键盘矩阵中的位置坐标(x2,y2)
	 * 需要满足x1<=x2&&y1<=y2;
	 * 
	 * @param x
	 *            键盘上的数字1
	 * @param y
	 *            键盘上的数组2
	 * @return 如果可以到达,返回true,反之,返回false
	 */
	static boolean reach(int x, int y) // 判断x能否到达y
	{
		Point pointX = locate(x); // 获取x的行 列
		Point pointY = locate(y); // 获取y的行 列
		return pointX.x <= pointY.x && pointX.y <= pointY.y;
	}

	public static void main(String[] args) {
		int T;
		Scanner scanner = new Scanner(System.in);
		T = scanner.nextInt();
		List<String> list = new ArrayList<String>();
		for (; T-- > 0;) {
			int[] indexNum = stringToIntArray(scanner.next());
			
			for (int i = 0; i < indexNum.length - 1; i++) // 因为后面有i+1操作,这里不能<length
			{
				// 如果第i(从左向右递增)位上的数字能够连接第i+1位上的数字,则继续判断i+1和i+2是否可达,如果都可打,则直接输出
				while (!reach(indexNum[i], indexNum[i + 1])) {
					if (--indexNum[i + 1] < 0)
						indexNum[i--]--;
					for (int j = i + 2; j < indexNum.length; j++)
						indexNum[j] = 9;
					//处理i=-1的情况
					if(i==-1)
						i=0;
				}
			}
			//添加到list中,集中打印
			list.add(intArrayToString(indexNum));
		}
		scanner.close();
		for (String string : list) {
			System.out.println(string);
		}
	}

	//测试获取键盘9的位置
	@Test
	public void testLocate() {
		System.out.println(locate(9));
	}

	//测试两个数字是不是可以到达
	@Test
	public void testReach() {
		System.out.println(reach(8, 9));
	}
	
	//char和int互转
	@Test
	public void testCharToInt() {
		System.out.println(Integer.parseInt('9' + ""));
		System.out.println(String.valueOf(9).charAt(0));
	}

}
//坐标类
class Point {
	public int x;
	public int y;

	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public String toString() {
		return "(x,y)=(" + x + "," + y + ")";
	}
}


发表于 2017-01-04 23:34:57 回复(0)
根据@ghost的思路,
C++程序如下:
#include <bits/stdc++.h>
vector<vector<char>> phone = {{'0'},
                              {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
                              {'0', '2', '3', '5', '6', '8', '9' },
                              {'3', '6', '9'},
                              {'0', '4', '5', '6', '7', '8', '9'},
                              {'0', '5', '6', '8', '9'},
                              {'6', '9'},
                              {'0', '7', '8', '9'},
                              {'0', '8', '9'},
                              {'9'}};

void solve(int i, string& s, vector<char>& res) {
    if (i >= s.size()) return;
    if (i == s.size()-1) {
        res.push_back(s[i]);
        return;
    }
    int line = s[i] - '0';
    if (find(phone[line].begin(), phone[line].end(), s[i+1]) != phone[line].end()) {
        res.push_back(s[i]);
        solve(i+1, s, res);
    }else {
        int k = static_cast<int> (phone[line].size()-1);
        while (phone[line][k] > s[i+1] && k >= 0) k--;
        if (k >= 0) {
            res.push_back(s[i]);
            res.push_back(phone[line][k]);
            for (++i; i < s.size()-1; ++i) res.push_back(*(phone[phone[line][k]-'0'].end()-1));
            return;
        }else {
            while (i >= 0) {
                s[i]--;
                if (i == 0) {
                    res.push_back(s[i]);
                    for (int j = 0; j < s.size() - 1; ++j) {
                        res.push_back(*(phone[s[i]-'0'].end()-1));
                    }
                    return;
                }
                else if (find(phone[s[i-1]-'0'].begin(), phone[s[i-1]-'0'].end(), s[i]) != phone[line].end()) {
                    res.push_back(s[i]);
                    for (int j = i+1; j < s.size(); ++j) {
                        res.push_back(*(phone[s[i]-'0'].end()-1));
                    }
                    return;
                }else {
                    res.pop_back();
                    i--;
                }
            }
        }
    }
}

int main() {
    int T;
    cin >> T;
    for(int m = 0; m < T; ++m) {
        string s;
        cin >> s;
        vector<char> res;
        solve(0, s, res);
        for(auto &item : res)
            cout << item;
        cout << endl;
    }
    return 0;
}

发表于 2016-12-01 10:48:46 回复(0)
import java.util.Arrays;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		int count = scan.nextInt();
		scan.nextLine();
		String[] array = new String[count];
		for (int i = 0; i < count; i++) {
			array[i] = scan.nextLine();
		}

		int[] niubi = { 00, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 33, 36, 39, 40, 44, 45,
				46, 47, 48, 49, 50, 55, 56, 58, 59, 66, 69, 70, 77, 78, 79, 80, 88, 89, 99 };

		for (String arrayi : array) {

			char[] num = arrayi.toCharArray();
			for (int i = 0; i < num.length - 1;) {
				char a = num[i];

				char b = num[i + 1];
				int tem = Integer.parseInt(("" + a + b));

				if (Arrays.binarySearch(niubi, tem) >= 0) {
					// System.out.println("okkkkkkkkk"+tem);
					i++;
				} else {
					// System.out.println("***kkkkk"+tem);
					int wtf = 0;
					for (int *** : niubi) {
						if (*** <= tem) {
							wtf = ***;
						} else {
							break;
						}
					}
					num[i] = (char) (wtf / 10 + 48);
					num[i + 1] = (char) (wtf % 10 + 48);
					for (int **** = i + 2; **** < num.length; ****++) {
						if (num[i] == '0')
							num[****] = '0';
						else
							num[****] = '9';
					}
					i = (i - 1) >= 0 ? i - 1 : 0;
				}

			}
			System.out.println(String.valueOf(num));

		}
	};
}
编辑于 2016-11-19 22:34:52 回复(0)
先建表,列表示前一个数字,行表示后一个数字。
1 表示对应行的数字后面可以跟对应列的数字,0 则相反。

#include<iostream>
#include<string.h>

using namespace std;

void subtrc(char a[],int k){//剪枝,从位置k开始修改数字,而不是从末尾开始每次只减少1
    int jw;//借位
    jw = -1;
    for(int i=k; i>=0&&jw!=0; i--){
        if(a[i]-'0'>0){
            a[i] += jw;
            jw = 0;
        }
        else{
            a[i] = '9';
            jw = -1;
        }
        for(int j=i+1;j<strlen(a);j++)//只要修改了还没到末尾数字,都需要将后面的置为9
            a[j] = '9';
    }
}

int main(){
    char chk[10][10]={
    {1,0,0,0,0,0,0,0,0,0},
    {1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,0,1,1,0,1,1},
    {0,0,0,1,0,0,1,0,0,1},
    {1,0,0,0,1,1,1,1,1,1},
    {1,0,0,0,0,1,1,0,1,1},
    {0,0,0,0,0,0,1,0,0,1},
    {1,0,0,0,0,0,0,1,1,1},
    {1,0,0,0,0,0,0,0,1,1},
    {0,0,0,0,0,0,0,0,0,1}
    };

    int t;
    char a[502];
    int p,r;
    int i,j;
    cin>>t;
    for(i=0;i<t;i++){
        cin>>a;
        while(1){
            for(j=1;j<strlen(a);j++){
                p = a[j-1]-'0';//获取前一个数字
                r = a[j]-'0';//获取当前数字
                if(chk[p][r]!=1)//查表,不满足条件
                    break;
            }
            if(j<strlen(a)){
                subtrc(a,j);
	    }
            else{
                cout<<a<<endl;
                break;
            }
        }
    }
}


编辑于 2016-10-10 16:03:48 回复(3)
亲测有效的代码,运行通过,不过有快200行。我的代码之所以行数多是因为我考虑更一般的情况。
比如把键盘换做1 2 3 4 等16进制,我的代码稍微修改就可以很好的解决。
                       5 6 7 8
                       9  A B  C
                       D  E  F  0
// numericKeypad.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int getInt(char a)
{
    return a + 1 - '1';
}
int getChar(int a)
{
    return a + '1' - 1;
}
void show(string maxNum)
{
    int i = 0;
    while(i<maxNum.size())
    {
        cout<< maxNum[i];
        i++;
    }
    cout << endl;

}

void getMaxNum(int keypad[][3], string array)
{
    //string array;
    string maxNum;
    //string temp = number;
    int digit,i,j,i1,j1,i0,j0,itemp,jtemp;
    /*if (number == 0)
    {
        cout << 0 << endl;
        return;
    }*/
    int flag = 0;//flag=1表示每一步都取当前能取到的最大值
    /*while (temp) {
        array.push_back(temp % 10);//高位的数字在数组末尾
        temp = temp / 10;
    }*/
    string::iterator it = array.begin();//高位的数字放在了数组首位
    maxNum.push_back(*it);//高位的数字在数组首部。
    int end = 0;//刚刚进入maxNum的数字的下标
    if (it != array.end()-1)
    {
    it++;   
    while (true)
    {   
        if (flag == 0)
        {

        digit = maxNum[end]+1-'1';
        if (digit != 0)
        {
            i = (digit - 1) / 3;
            j = (digit - 1) % 3;
        }
        else
        {
            i = 3;
            j = 1;
        }
        i1 = (getInt(*it) - 1) / 3;
        j1 = (getInt(*it) - 1) % 3;
        if (i1 >= i&&j1 >= j) {//判断下一个数字是否可以到达
            maxNum.push_back(*it);
            if (it == (array.end() - 1))
            {
                break;
            }
            end++;
            it++;
        }
        else
        {
            if (digit <= getInt(*it) ||( 3 >= i&&1 >= j))
            {
                if (digit <= getInt(*it))
                {
                    for (i0 = i; i0 <= 2; i0++)
                    {
                        for (j0 = j; j0 <= 2; j0++)
                        {
                            if (keypad[i0][j0] < getInt(*it))
                            {
                                itemp = i0;
                                jtemp = j0;
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (keypad[i0][j0] > getInt(*it))
                        {
                            break;
                        }
                    }
                }
                else
                {
                    itemp = 3;
                    jtemp = 1;
                }   
                maxNum.push_back(getChar(keypad[itemp][jtemp]));               
                if (it == (array.end()-1))
                {
                    break;
                }
                it++;
                end++;
                flag = 1;
            }
            else
            {
                if (maxNum.size() == 1)
                {
                    maxNum[maxNum.size() - 1] = getChar( getInt(maxNum[maxNum.size() - 1]) - 1 );
                    flag = 1;
                }
                else
                {
                    while (digit >= getInt(maxNum[maxNum.size() - 2]))
                    {
                        digit = digit - 1;
                        if (((digit - 1) / 3) >= ((getInt(maxNum[maxNum.size() - 2]) - 1) / 3) && ((digit - 1) % 3) >= ((getInt(maxNum[maxNum.size() - 2]) - 1) % 3))
                        {
                            maxNum[maxNum.size() - 1] = getChar(digit);
                            flag = 1;
                            break;
                           
                        }
                        continue;
                    }   
                    if (digit < getInt(maxNum[maxNum.size() - 2]))
                    {
                        maxNum.pop_back();
                        maxNum[maxNum.size() - 1]= getChar(getInt(maxNum[maxNum.size() - 1]) -1);
                        it--;
                        flag = 1;
                    }
                }
            }
        }
    }//flag
    else
    {
        if (getInt(maxNum[maxNum.size() - 1]) == 0)
        {
            maxNum.push_back('0');
            if (it == (array.end()-1))
            {
                break;
            }
            it++;
        }
        else
        {
            maxNum.push_back('9');
            if (it == (array.end() - 1))
            {
                break;
            }
            it++;
        }
    }
    }



    }
   
    show(maxNum);
}



int main()
{
    int keypad[4][3] = { 1,2,3,4,5,6,7,8,9,-1,0,-1 };
    int n;
    cin >> n;
    string *number=new string[n];
    int i = 0;
    while (i<n) {
        cin>>number[i];
        i++;
    }
    for (i = 0; i < n; i++)
    {
        getMaxNum(keypad, number[i]);
    }

    return 0;
}


  
发表于 2016-04-21 22:16:47 回复(0)
根据题意,可以知道的是,按下某个键后,这个键左方及上方的键不能再用了。例如按下了[5]:




所以我们可以得到一张表,以表示按下某个键后还剩下的合法按键:



同时,我们模拟一下按键的过程,例如给出的数是k = 99099

[9][9][0]     //[0]不合法,且没有小于[0]的按键,回溯到第一次按[9]

[8][9][9][9][9] //已知[9]不合法,按下[8],后面无论怎么按都不会大于k
//所以后面全部按按下[8]后的最大合法按键[9]


到此,我们可以总结出一套算法:

1、从高位开始(数字的高位,数组中的低位,按字符串储存的话);

2、从不大于当前数位的合法按键中从大到小枚举,

若有合法按键存在且等于当前数位,跳到下一位,重复2

若没有,则回溯;

若小于当前数位,那么后面的所以数位则填充当前最大的合法值,结束;

3、重复2直到低位结束;

=-=代码就不贴出来了


编辑于 2015-05-05 19:55:26 回复(8)
#include <iostream>
using namespace std;
void locate(int digit,int &x,int &y)
{
    digit=digit?--digit:10;
    x=digit/3;  //行数
    y=digit%3;  //列数
}
bool reach(int x,int y)   //判断x能否到达y
{
    int x0,y0,x1,y1;
    locate(x-'0',x0,y0);  //获取x的行 列
    locate(y-'0',x1,y1);  //获取y的行 列
    return x0<=x1&&y0<=y1;
}
int main()
{
    int T;
    for(cin>>T;T--;)
    {
        string K;
        cin>>K;
        for(int i=0;i<K.size()-1;i++) //个位不用参加循环
        {
            while(!reach(K[i],K[i+1]))
            {
                if(--K[i+1]<0)
                    K[i--]--;
                for(int j=i+2;j<K.size();j++)
                    K[j]='9';
            }
        }
        cout<<K<<endl;
    }
}
编辑于 2016-09-04 18:05:28 回复(8)
// 主要是中间位为0的处理,采用从低位到高位可避免向高位借位的麻烦。
#include<iostream>
#include<string>
#include<vector>
using namespace std;

const vector<string> helper = { "0", "0123456789", "0235689", "369",
"0456789", "05689", "69", "0789", "089", "9" };
int main(){
	int num;
	while (cin >> num){
		vector<string> vStr(num);
		for (int i = 0; i < num; ++i){
			cin >> vStr[i];
		}
		for (string str : vStr){
			for (int i = str.size() - 2; i >= 0; --i){ // 逆序(低位->高位
				while (helper[str[i] - '0'].find(str[i + 1]) == -1){					
					if (str[i + 1] == '0'){
						str[i]--;
						str[i + 1] = '9';
					}else
						str[i + 1]--;                    
                    for (int j = i + 2; j < str.size(); ++j)
                        str[j] = '9';
				}
                if(str[i+1] == '0'){ //这点是因为后置位都变为9,而0后面只可跟0
                    for (int j = i + 1; j < str.size(); ++j)
                        str[j] = '0';
                }
			}
			cout << str << endl;
		}
	}
	return 0;
}
// 借鉴 Glenn_Gould 方法,从高位到低位
#include<iostream>
#include<string>
#include<vector>
using namespace std;

const vector<string> helper = { "0", "0123456789", "0235689", "369",
"0456789", "05689", "69", "0789", "089", "9" };
int main(){
	int num;
	while (cin >> num){
		vector<string> vStr(num);
		for (int i = 0; i < num; ++i){
			cin >> vStr[i];
		}
		for (string str : vStr){
			for (int i = 0; i < str.size() - 1; ++i){ // 正序
				while (helper[str[i] - '0'].find(str[i + 1]) == -1){					
					if (str[i + 1]-- == '0'){
						str[i--]--;
					}
					for (int j = i + 2; j < str.size(); ++j)
						str[j] = '9';
					if (i < 0) // 当i--到最高位时避免越界,也可理解为再一次循环检查
						i++;
				}
			}
			cout << str << endl;
		}
	}
	return 0;
}

编辑于 2017-05-13 20:13:11 回复(1)
//根据别人思路写的、发现最难的是容易把pad和last数组写错/(ㄒoㄒ)/~~
#include<iostream>
#include<string>
using namespace std;
int pad[10][10]={
    {0},
    {0,1,2,3,4,5,6,7,8,9},
    {0,2,3,5,6,8,9},
    {3,6,9},
    {0,4,5,6,7,8,9},
    {0,5,6,8,9},
    {6,9},
    {0,7,8,9},
    {0,8,9},
    {9,}

};
int last[]={0,9,6,2,6,4,1,3,2,0};
string num;
int n;
bool st;
bool test(int index,int n){
    for(int i=index;i<num.size();i++){
        int ts=num[i]-'0';

        if(n==ts){
            n=pad[n][0];
            continue;
        }else if(n<ts){
            return true;
        }else{
            return false;
        }
    }
    return true;
}
int main(){
    //如果非st就尽量大
    //如果st就看后面最小的能不能满足
    int t;
    cin>>t;
    while(t--){
      cin>>num;
      int n=num.size();
      st=true;
      string ans;
      int now=1;
      for(int i=0;i<num.size();i++){
          int ts=num[i]-'0';
          if(st){
              for(int j=last[now];j>=0;j--){
                  if(pad[now][j]>ts){
                      continue;
                  }else if(pad[now][j]==ts){
                      if(test(i,pad[now][j])){
                          now=pad[now][j];
                      }else{
                         st=false;
                      	 now=pad[now][j-1];
                      }
                  }else{
                      st=false;
                      now=pad[now][j];
                  }
                  ans+='0'+now;;
                  break;
              }
          }else{
              ans+=(char)('0'+pad[now][last[now]]);
              now=pad[now][last[now]];
          }
      }
        cout<<ans<<endl;
    }

}

发表于 2016-03-26 20:40:40 回复(0)
// 递归调用 用例的值很大输出不能用整形
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;

map<int, vector<int>>lessMap = {{0, {0}},
                            {1, {0123456789}},
                            {2, {0235689}},
                            {3, {369}},
                            {4, {0456789}},
                            {5, {05689}},
                            {6, {69}},
                            {7, {0789}},
                            {8, {089}},
                            {9, {9}}};

string findMax(const string &inputint indexconst vector<int&lbool isMax)
{
    if(index==input.length()){ return "";}
    int n = isMax?9 :input[index]-48;
    for(int i=l.size()-1; i>=0; i--)
    {
        int max = l[i];
        if(max<=n)
        {
            if(max<n){ isMax=true;}
            string next = findMax(input, index+1lessMap[max], isMax);
            if(next!="error"){
                return to_string(max)+next;
            }
        }
    }
    return "error";
}

int main() {
    int T;
    cin >> T;
    while(T--)
    {
        string input;
        cin >> input;
        int index =0;
        vector<int> l = {0123456789};
        string result = findMax(input, index, l, false);
        cout << result << endl;

    }
}
// 64 位输出请用 printf("%lld")
发表于 2022-11-04 17:59:24 回复(0)
#include <iostream>
using namespace std;
void locate(int digit, int &x, int &y){
    digit = digit?--digit:10;
    x=digit/3;
    y=digit%3;
}

bool reach(int x, int y){
    int x0, x1, y0, y1;
    locate(x-'0',x0, y0);
    locate(y-'0',x1, y1);
    return x0<=x1 && y0<=y1;
}

int main(){
    int T;
    for(cin>>T;T--;){
        string K;
        cin>>K;
        for(int i=0;i<K.size()-1;i++){
            while(!reach(K[i], K[i+1])){
                if(--K[i+1]<'0')
                    K[i--]--;
                for(int j=i+2;j<K.size();j++)
                    K[j]='9';
            }
        }
        cout<<K<<endl;
    }
}
发表于 2022-03-19 17:06:12 回复(2)
/*解题思路:

对输入数字从大到小进行分析,如 131,依次看 13 31 是否符合规律
如13 符合,31,不符合规律,看30是否符合,如果30不符合,则变为29,由于进位了,所以向上看一级,再看12是否符合,如12符合,在看29是否符合 ,0变9,则上一级减1 

另外,如果上一级减1,则后面的都置9。比如30000,前两位30,不符合规律,则变为29,后面的数字都置为9,变为29999

效率不知啥原因,一直不太高,最小7ms,看来方法还有优化空间。大家如采用此方法有优化点的也帮忙提出来。
 
*/

#include <iostream>
#include <string>

using namespace std;
int n;

//不符合规律的表
char d[10][11] = {"123456789","","147","1245780","123","12347","12345780","123456","1234567","123456780"};

//采用查表法,看看是否符合规律
bool check(char a1, char a2){
    int j;
    
    int m = a1 - '0';
    
    j = 0;
    while(d[m][j]){
        if(a2 == d[m][j])
            return false;        //不符合 
        j++;
    }

    return true;                //符合规律 
}

int main(){
    int i, j, t;
    string a[40];
    
    cin >> n;
    
    for(i = 0; i < n; i ++)
        cin >> a[i];
        
    for(i = 0; i < n; i ++){
        j = 0;
        while(j < a[i].length() -1){
            if(!check(a[i][j],a[i][j+1])){    //不符合规律,前两位进行处理,采用减1法,但注意减完后,后续位置要都置为9
                //a[i][j+1] 减 1 
                if(a[i][j+1] != '0'){
                    a[i][j+1] -= 1;            //不等于0,直接减1,重新检测是否符合规律                    

                }else{
                    //从后向前找一个不等0的减1,注意后面的要都置为9
                    int t = j + 1; 
                    do{
                        a[i][t] = '9'; 
                        t --;
                    }while(a[i][t] == '0');
                    
                    a[i][t] -= 1;
                    j = (t > 0) ? j = t - 1 : 0;    //让j 从变化的上一个位置重新检测         
                }
                
                //上一位减1后,后面都置 9 
                for(t = j + 2; t < a[i].length(); t++)
                    a[i][t] = '9';
                    
            }else
                j ++;        //如果j 和 j +1 符合规律,则向下检测 
        }
        cout << a[i] << '\n';
    }

发表于 2019-03-15 10:35:44 回复(0)
lst = [None for i in range(10)]
lst[0]=['0']
lst[1]=['0','1','2','3','4','5','6','7','8','9']
lst[2]=['0','2','3','5','6','8','9']
lst[3]=['3','6','9']
lst[4]=['0','4','5','7','6','8','9']
lst[5]=['0','5','6','8','9']
lst[6]=['6','9']
lst[7]=['0','7','8','9']
lst[8]=['0','8','9']
lst[9]=['9']
lst[0]=['0']
n = input()
n = int(n)
for i in range(n):
    nu = input()
    num = []
    for i in nu:
        num.append(i)
    index = -1
    for i in range(len(num)-1):
        if num[i+1] not in lst[int(num[i])]:
            if num[i+1]>=min(lst[int(num[i])]):
                for k in range(len(lst[int(num[i])])):
                    if lst[int(num[i])][k]>num[i+1]:
                        break
                num[i+1]=lst[int(num[i])][k-1]
                index = i+2
                break
            else:
                te = str(num[i])
                if num[i]!='9' and i>0:
                    num[i] = lst[int(num[i-1])][lst[int(num[i-1])].index(te)-1]
                    index = i+1
                    break
                elif num[i]=='9' and i>0:
                    te = int(i)-1
                    while te>=0 and num[te]=='9':
                        te-=1
                    num[te+1] = str(8)
                    index=te+2
                    break
                elif i==0:
                    num[0] = str(int(num[0])-1)
                    index=1
                    break
    if index!=-1:
        for j in range(index,len(num)):
            num[j] = max(lst[int(num[j-1])])
    out = ''
    for i in num:
        out+=i
    print(out)
一道五颗星的题,纪念一下。。。代码写的有点乱。主要的思路是顺着输入数由高位到低位查找。如果发现下一位的数在上一位可能键入的数字列表中没有,则先考虑保留上一位的数不变,取下一位为上一位可能键入的数字列表中紧挨着当前数的数字。但是如果数字列表中的数都比它要大,那么就只好把上一位的数给减小了。其中‘9’这个数字比较特殊,因为可能出现:9993,9899等情况,要分开讨论。
发表于 2018-12-16 10:16:04 回复(0)
x = [10]*10
x[0]=[0]
x[1]=[1,2,3,4,5,6,7,8,9,0]
x[2]=[2,3,5,6,8,9,0]
x[3]=[3,6,9]
x[4]=[4,5,6,7,8,9,0]
x[5]=[5,6,8,9,0]
x[6]=[6,9]
x[7]=[7,8,9,0]
x[8]=[8,9,0]
x[9]=[9]

T=int(input())
for t in range(T):
    K=list(input())
    for i in range(len(K)-1):
        while int(K[len(K)-1-i]) not in x[int(K[len(K)-2-i])]:#从低位往高位遍历
            if K[len(K)-i-1] == '0':#低位等于0且不在高位的下一步中
                K[len(K)-i-2] = str(int(K[len(K)-i-2])-1)#高位数字-1
                K[len(K)-i-1] = '9'#低位为9
            else:#低位不为0
                K[len(K)-i-1] = str(int(K[len(K)-1-i]) -1)#低位-1
            if len(K)-i < len(K):#当低位不是最后一位时
                for j in range(len(K)-i,len(K)):#要么这一位减了1,要么前一位减了1
                    K[j] = '9'#后面全部的变成 9才能最接近给的数字
        if K[len(K)-i-1] =='0' :#低位在高位的下一步中且低位为0
            if len(K)-i < len(K):#不是最后一位
                for j in range(len(K)-i,len(K)):#0后面只能是0
                    K[j] = '0'
    print(''.join(K))

发表于 2018-09-30 17:02:20 回复(0)
import java.util.Scanner;
public class Main{
    public static String[] dp={ "0", "0123456789", "0235689", "369","0456789", "05689", "69", "0789", "089", "9" };
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int t = input.nextInt();
        input.nextLine();
        while(t-->0){
            String result="",s=input.nextLine();
            boolean flag=false;
            int i=0;
            for(;i<s.length()-1;i++){
                if(judge(s.charAt(i),s.charAt(i+1))){
                    result+=s.charAt(i);
                }else{
                    flag=true;
                    break;
                }
            }
            if(flag){
                while(i>=0&&less(s.charAt(i),s.charAt(i+1)).equals("")){
                    //System.out.println("work");
                    if(i==0){
                        result=String.valueOf(((int)s.charAt(i)-48-1));
                        while(i++<s.length()-1){
                            int l=dp[(int)result.charAt(0)-48].length();
                            result+=dp[(int)result.charAt(0)-48].charAt(l-1);
                        }
                        break;
                    }
                    i--;
                    result=result.substring(0,result.length()-1);
                }
                if(i<s.length()){
                    String p=less(s.charAt(i),s.charAt(i+1));
                    result+=s.charAt(i++);
                    result+=p;
                    while(i++<s.length()-1){
                        int l=dp[Integer.parseInt(p)].length();
                        result+=dp[Integer.parseInt(p)].charAt(l-1);
                    }
                }
            }else{
                result+=s.substring(s.length()-1, s.length());
            }
            System.out.println(result);
        }
    }
    public static boolean judge(char a,char b){
        if(dp[(int)a-48].contains(String.valueOf(b))) return true;
        else return false;
    }
    public static String less(char a,char b){
        int index=-1;
        int temp=(int)b-48;
        while(index<0&&temp>=0){
            index=dp[(int)a-48].indexOf(String.valueOf(--temp));
        }
        if(index<0) 
            return "";
        else
            return String.valueOf(dp[(int)a-48].charAt(index));
    }
}
发表于 2018-08-23 11:17:32 回复(1)
/*bfs + 优先队列*/
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<stdlib.h>
#include<vector>
#include<math.h>
#include<map>
#include<queue>
using namespace std;
bool check(char c, char nc){
    switch(c){
        case '1':
            return true;
            break;
        case '2':
            if(nc == '1' || nc == '4' || nc == '7') return false;
            return true;
            break;
        case '3':
            if(nc == '3' || nc == '6' || nc == '9') return true;
            return false;
            break;
        case '4':
            if(nc == '1' || nc == '2' || nc == '3') return false;
            return true;
            break;
        case '5':
            if(nc == '5' || nc == '6' || nc == '8' ||nc == '9' || nc == '0') return true;
            return false;
            break;
        case '6':
            if(nc == '6' || nc == '9') return true;
            return false;
            break;
        case '7':
            if(nc == '7' || nc == '8' || nc == '9' || nc == '0') return true;
            return false;
            break;
        case '8':
            if(nc == '8' || nc == '9' || nc == '0') return true;
            return false;
            break;
        case '9':
            if(nc == '9') return true;
            return false;
            break;
        case '0':
            if(nc == '0') return true;
            return false;
            break;
    }
    return false;
}
int main(){
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--){
        string s;
        cin>>s;
        priority_queue<string> q;
        string p = "0123456789";
        for(int i=0;i<p.length();i++){
            if(check('1', p[i])){
                string tmp = "";
                tmp += p[i];
                q.push(tmp);
            }
        }
        while(!q.empty()){
            string top = q.top();
            q.pop();
            if(top.length() >= s.length()){
                cout<<top;
                break;
            }
            char back = top.back();
            for(int i=0;i<p.length();i++){
                if(check(back, p[i])){
                    string tmp = top + p[i];
                    if(tmp > s) continue;
                    q.push(tmp);
                }
            }
        }
        cout<<endl;
    }
    return 0;
}

发表于 2018-07-07 14:20:34 回复(0)

问题信息

难度:
55条回答 13294浏览

热门推荐

通过挑战的用户

查看代码
Numeric Keypad