(200分)- 九宫格按键输入(Java & JS & Python)
题目描述
九宫格按键输入,输出显示内容,有英文和数字两个模式,默认是数字模式,数字模式直接输出数字,英文模式连续按同一个按键会依次出现这个按键上的字母,如果输入”/”或者其他字符,则循环中断。
字符对应关系如图:
要求输入一串按键,输出屏幕显示。
输入描述
输入范围为数字 0~9 和字符’#’、’/’,输出屏幕显示,例如,
在数字模式下,输入 1234,显示 1234
在英文模式下,输入 1234,显示,adg
输出描述
#用于切换模式,默认是数字模式,执行#后切换为英文模式;
/表示延迟,例如在英文模式下,输入 22/222,显示为 bc;
英文模式下,多次按同一键,例如输入 22222,显示为 b;
用例
| 输入 | 123#222235/56 |
| 输出 | 123adjjm |
题目解析
本题考察逻辑分析能力和栈结构的应用。
解题思路如下:
初始化:
- 定义栈stack存储结果
- 设置isEng标志记录当前模式(false为数字模式,true为英文模式),初始为false
遍历字符串s的每个字符c:
- 遇到'#':切换模式前需检查:
- 若当前为英文模式,需先处理栈顶数字的转换
- 然后切换模式:isEng = !isEng
- 遇到'/':处理循环中断
- 仅当英文模式时才需处理栈顶数字转换
- 其他字符:
- 数字模式:直接入栈
- 英文模式:
- 栈顶字符与c不同:需中断循环(转换栈顶数字)
- 相同:增加栈顶数字的重复计数
- 遇到'#':切换模式前需检查:
循环中断逻辑的注意事项:
- 必须处于英文模式
- 栈不能为空
Java算法源码
import java.util.LinkedList; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println(getResult(sc.nextLine())); } static String[] dict = {" ", ",.", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; static LinkedList<Character> stack = new LinkedList<>(); static int topRepeat = 0; static boolean isEng = false; public static String getResult(String s) { s += " "; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '#': // 如果输入”/”或者其他字符,则循环中断 interrupt(); // #用于切换模式 isEng = !isEng; break; case '/': // 如果输入”/”或者其他字符,则循环中断 interrupt(); break; default: // 数字模式 // 直接输出数字 if (!isEng) { stack.add(c); break; } // 英文模式,需要检查栈顶 // 如果栈顶不是英文模式字符(这里可以基于topRepeat判断,topRepeat是英文模式下对应按键的重复次数,如果为0,则说明栈顶存储的不是英文模式字符),则缓存对应字符c,并记录重复次数 if (topRepeat == 0) { stack.add(c); topRepeat++; break; } // 如果栈顶字符有重复次数,则此时需要比较当前按键c和之前重复的按键stack.getLast是否相同 if (c != stack.getLast()) { // 如果输入”/”或者其他字符,则循环中断 interrupt(); stack.add(c); } topRepeat++; } } StringBuilder sb = new StringBuilder(); for (int i = 0; i < stack.size() - 1; i++) sb.append(stack.get(i)); return sb.toString(); } // 英文模式连续按同一个按键会依次出现这个按键上的字母,如果输入”/”或者其他字符,则循环中断 // interrupt用于处理循环中断后的逻辑 public static void interrupt() { if (!isEng || stack.size() == 0 || topRepeat == 0) return; stack.add(map(stack.removeLast(), topRepeat)); topRepeat = 0; } // 基于dict,获取一个数字c被重复repeat次后,对应的字符 public static char map(char c, int repeat) { int num = Integer.parseInt(c + ""); String s = dict[num]; int i = (repeat - 1) % s.length(); return s.charAt(i); } }JS算法源码
/* JavaScript Node ACM模式 控制台输入获取 */ const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const stack = []; let topRepeat = 0; let isEng = false; rl.on("line", (line) => { console.log(getResult(line)); // 如果需要测试多组用例,这里需要将全局变量重置 stack.length = 0; topRepeat = 0; isEng = false; }); function getResult(s) { s += " "; for (let c of s) { switch (c) { case "#": // 如果输入”/”或者其他字符,则循环中断 interrupt(); // #用于切换模式 isEng = !isEng; break; case "/": // 如果输入”/”或者其他字符,则循环中断 interrupt(); break; default: // 数字模式直接输出数字 if (!isEng) { stack.push(c); break; } // 英文模式,需要检查栈顶 // 如果栈顶不是英文模式字符(这里可以基于topRepeat判断,topRepeat是英文模式下对应按键的重复次数,如果为0,则说明栈顶存储的不是英文模式字符),则缓存对应字符c,并记录重复次数 if (topRepeat == 0) { stack.push(c); topRepeat++; break; } // 如果栈顶字符有重复次数,则此时需要比较当前按键c和之前重复的按键stack.getLast是否相同 if (c != stack.at(-1)) { // 如果输入”/”或者其他字符,则循环中断 interrupt(); stack.push(c); } topRepeat++; } } return stack.slice(0, stack.length - 1).join(""); } // 英文模式连续按同一个按键会依次出现这个按键上的字母,如果输入”/”或者其他字符,则循环中断 // interrupt用于处理循环中断后的逻辑 function interrupt() { if (!isEng || stack.length == 0 || topRepeat == 0) return; stack.push(map(stack.pop(), topRepeat)); topRepeat = 0; } const dict = [ " ", ",.", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz", ]; // 基于dict,获取一个数字c被重复repeat次后,对应的字符 function map(c, repeat) { const num = parseInt(c); const s = dict[num]; const i = (repeat - 1) % s.length; return s[i]; }Python算法源码
# 输入获取 s = input() # 全局变量 stack = [] topRepeat = 0 isEng = False dictionary = (" ", ",.", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz") # 基于dictionary,获取一个数字c被重复repeat次后,对应的字符 def mapping(c, repeat): num = int(c) s1 = dictionary[num] i = (repeat - 1) % len(s1) return s1[i] # 英文模式连续按同一个按键会依次出现这个按键上的字母,如果输入”/”或者其他字符,则循环中断 # interrupt用于处理循环中断后的逻辑 def interrupt(): global topRepeat if not isEng or len(stack) == 0 or topRepeat == 0: return stack.append(mapping(stack.pop(), topRepeat)) topRepeat = 0 # 算法入口 def getResult(): global s global isEng global topRepeat s += " " for c in s: if c == '#': # 如果输入”/”或者其他字符,则循环中断 interrupt() # #用于切换模式 isEng = not isEng elif c == '/': # 如果输入”/”或者其他字符,则循环中断 interrupt() else: # 数字模式直接输出数字 if not isEng: stack.append(c) continue # 英文模式,需要检查栈顶 # 如果栈顶不是英文模式字符(这里可以基于topRepeat判断,topRepeat是英文模式下对应按键的重复次数,如果为0,则说明栈顶存储的不是英文模式字符),则缓存对应字符c,并记录重复次数 if topRepeat == 0: stack.append(c) topRepeat += 1 continue # 如果栈顶字符有重复次数,则此时需要比较当前按键c和之前重复的按键stack.getLast是否相同 if c != stack[-1]: # 如果输入”/”或者其他字符,则循环中断 interrupt() stack.append(c) topRepeat += 1 return "".join(stack[:-1]) # 算法调用 print(getResult())