华为OD机试 九宫格按键输入

题目描述

九宫格按键输入,输出显示内容,有英文和数字两个模式,默认是数字模式,数字模式直接输出数字,

英文模式连续按同一个按键会依次出现这个按键上的字母,如果输入 ‘/’ 或者其他字符,则循环中断。

字符对应关系如图所示。

要求输入一串按键,输出屏幕显示内容。

输入描述

输入范围为数字 0~9 和字符 ‘#’、’/’,输出屏幕显示,例如:

在数字模式下,输入 1234,显示 1234

在英文模式下,输入 1234,显示,adg

输出描述

#用于切换模式,默认是数字模式,执行 # 后切换为英文模式;

/ 表示延迟,例如在英文模式下,输入 22/222,显示为 bc;

英文模式下,多次按同一键,例如输入 22222,显示为 b;

示例 1

输入

123

输出

123

示例 2

输入

#22/23044444411

输出

bad i.

Java源码解析

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;


public class JiuGongGe {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        scanner.close();
        String result = getDisplayResult(input);
        System.out.println(result);
    }

    private static String getDisplayResult(String input) {
        Map<Character, String> characterStringMap = buildMap();
        boolean isNumber = true;
        StringBuffer stringBuffer = new StringBuffer();
        int inputLength = input.length();
        for (int i = 0; i < inputLength; i++) {
            char ch = input.charAt(i);
            // # 切换输入法
            if (ch == '#') {
                isNumber = !isNumber;
                continue;
            }
            // '/' 不拼接
            if (ch == '/') {
                continue;
            }
            // 数字直接拼接
            if (isNumber) {
                stringBuffer.append(ch);
                continue;
            }
            // 英文输入法拼接 空格
            if (ch == '0') {
                stringBuffer.append(" ");
                continue;
            }
            // 英文输入法时:统计重复字符数量
            int repeatCharNum = getRepeatCharNum(input, inputLength, ch, i);

            // 向右移动指针,将重复的字符剔除(连续重复字符最终只输入一个字符)
            i = i + repeatCharNum;
            // 1 对应 ",.", 2 对应 "abc" 等
            String ziMu = characterStringMap.get(ch);
            if (repeatCharNum > 0) {
                int i1 = repeatCharNum % ziMu.length();
                stringBuffer.append(ziMu.charAt(i1));
            } else {
                // 没有重复字母直接输出
                stringBuffer.append(ziMu.charAt(repeatCharNum));
            }
        }
        return stringBuffer.toString();
    }

    private static int getRepeatCharNum(String input, int inputLength, char ch, int i) {
        int repeatCharNum = 0;
        for (int j = i + 1; j < inputLength; j++) {
            char next = input.charAt(j);
            // '/'表示中断连续
            if (next == '/') {
                break;
            }
            // 当前字符不等于下一个字符
            if (ch != next) {
                break;
            }
            repeatCharNum++;
        }
        return repeatCharNum;
    }

    private static Map<Character, String> buildMap() {
        Map<Character, String> map = new HashMap<>();
        map.put('1', ",.");
        map.put('2', "abc");
        map.put('3', "def");
        map.put('4', "ghi");
        map.put('5', "jkl");
        map.put('6', "mno");
        map.put('7', "pqrs");
        map.put('8', "tuv");
        map.put('9', "wxyz");
        return map;
    }
}

栈结构解法

本题看上去就是一道逻辑题,但是可以利用栈结构来处理。

本题的主要难点在于处理英文模式下的输入。

首先,英文模式下,如果输入的是0-9的数字的话,则是需要转为对应的英文,但是由于我们可以输入多次重复数字,来切换对应于同一个数字的英文,比如英文模式下,输入222,即对应c,输入22,即对应b,输入2,即对应a,输入2222,又对应a

因此,英文模式下的输入,我们不应该直接将输入的数字转为英文,而是应该缓存输入数字的重复次数,在下一次输入不同的数字或者输入'/'时,则需要将重复的数字输入转为对应英文。

我的解题思路是,遍历输入字符串的每一个字符,并尝试将它们压入stack栈中,而在压栈前,需要先检查stack栈顶元素top是否为一个数组,若为数组,则数组对应一个尚未转化成英文的输入,数组元素含义为:[ 数字,重复次数 ]

此时,如果输入模式mode是数字模式,或者是英文模式下输入的'/',再或者输入模式mode是英文模式,但是输入的字符(即遍历的字符)和栈顶top数组的top[0]数字不同的话,则此时我们需要将栈顶top数组转为英文。

转化规则为:

比如top = [2, 5],即英文模式下,按了52,此时应该输出英文b

按键2对应的英文 arr = ['a', 'b','c'] len = arr.length ,count=5

因此top = [2, 5] 对应的英文为 arr[(count-1)% len],即 arr[4%3]= arr[1]

当我们将栈顶数组转为英文后,再考虑将遍历的字符压入栈顶,但是需要注意的是,如果遍历的字符是数字,且在数字模式下输入,则直接压入栈顶,若是英文模式下的输入,则需要转为[num1]数组下入栈顶,即数字num被重复按了1次。

如果栈顶数组的top[0],和英文模式下,输入的数字相同,则top[1]++,表示英文模式下,top[0]数字又被按了一次。

而栈顶元素不是数组时的处理方案,和上面将栈顶数组转为英文后的操作一致。

JavaScript算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");
 
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
 
rl.on("line", (line) => {
  const arr = [...line];
 
  console.log(getResult(arr));
});
 
function getResult(arr) {
  const map = [
    " ",
    ",.",
    "abc",
    "def",
    "ghi",
    "jkl",
    "mno",
    "pqrs",
    "tuv",
    "wxyz",
  ];
 
  const stack = [];
 
  let mode = true; // true为数字模式,false为英文模式
 
  arr.forEach((char) => {
    switch (char) {
      case "#":
        mode = !mode;
        break;
      case "/":
        if (!mode) ipt(mode, stack, map);
        break;
      default:
        ipt(mode, stack, map, char);
    }
  });
 
  ipt(mode, stack, map);
 
  return stack.join("");
}
 
function ipt(mode, stack, map, char) {
  const top = stack[stack.length - 1];
 
  if (Array.isArray(top)) {
    if (!mode && top[0] == char) {
      return top[1]++;
    } else {
      const [num, count] = stack.pop();
 
      const arr = map[num];
      const len = arr.length;
 
      stack.push(arr[(count - 1) % len]);
    }
  }
 
  if (char) {
    if (mode) {
      stack.push(char);
    } else {
      stack.push([char, 1]);
    }
  }
}

#华为OD机试#
全部评论
切换输入法这写错了 isNumber = !isNumber;
点赞 回复 分享
发布于 2023-01-17 14:29 广东
Jkl!
点赞 回复 分享
发布于 2023-02-26 20:17 上海
好像是牛客的原题
点赞 回复 分享
发布于 2023-02-28 00:04 北京

相关推荐

不愿透露姓名的神秘牛友
09-30 19:49
起名星人:蛮离谱的,直接要求转投销售
投递汇川技术等公司10个岗位
点赞 评论 收藏
分享
评论
7
13
分享
牛客网
牛客企业服务