8.30美团技术岗算法第一题

发布于:2025-09-03 ⋅ 阅读:(19) ⋅ 点赞:(0)

题目

说明

福利题也不白给,算术题肯定考大数处理,求余题肯定靠找规律

技术积累

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

StringTokenizer st = new StringTokenizer(br.readLine());

这种方法和new Scanner(System.in)有什么区别?

功能 BufferedReader + StringTokenizer Scanner
读取单位 主要按 “行” 读取(readLine()),需手动分割行内数据 可按 “分隔符”(默认空格、换行等)读取,支持 nextInt()nextLong() 等直接读单个数据
类型转换 需手动转换(如 Integer.parseInt()new BigInteger(...) 内置类型转换方法(如 nextInt()nextBigInteger()),无需手动解析
分隔符支持 StringTokenizer 仅支持固定分隔符(默认空白字符,可自定义单字符分隔符) 支持正则表达式作为分隔符(如 `scanner.useDelimiter (", ;")` 按逗号或分号分割)
异常处理 必须显式处理 IOException(受检异常) 无需处理受检异常(内部转换为非受检异常 InputMismatchException

代码

import java.util.*;
import java.math.BigInteger;
import java.io.*;

public class NumberOperations {
    
    /**
     * 高效的数字操作算法
     * 规则:偶数除以2,奇数乘以3加1
     * 使用BigInteger处理大数,并进行优化避免超时
     */
    public static BigInteger solve(BigInteger n, long k) {
        // 如果k为0,直接返回n
        if (k == 0) {
            return n;
        }
        
        // 使用记忆化存储已计算的结果,避免重复计算
        Map<BigInteger, BigInteger> memo = new HashMap<>();
        
        // 优化:如果n变成1,后续操作会形成循环 1->4->2->1
        // 可以直接计算最终结果
        BigInteger current = n;
        long operations = k;
        
        while (operations > 0) {
            // 检查是否进入1-4-2-1循环
            if (current.equals(BigInteger.ONE)) {
                return handleCycle(operations);
            }
            if (current.equals(BigInteger.valueOf(2))) {
                return handleCycleFrom2(operations);
            }
            if (current.equals(BigInteger.valueOf(4))) {
                return handleCycleFrom4(operations);
            }
            
            // 检查记忆化
            if (memo.containsKey(current)) {
                current = memo.get(current);
                operations--;
                continue;
            }
            
            BigInteger original = current;
            
            // 执行操作
            if (current.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
                // 偶数:除以2
                current = current.divide(BigInteger.valueOf(2));
            } else {
                // 奇数:乘以3加1
                current = current.multiply(BigInteger.valueOf(3)).add(BigInteger.ONE);
            }
            
            // 存储到记忆化表
            memo.put(original, current);
            operations--;
            
            // 优化:连续除以2的情况
            if (operations > 0 && current.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
                // 计算可以连续除以2多少次
                long consecutiveDivisions = Math.min(operations, countTrailingZeros(current));
                if (consecutiveDivisions > 0) {
                    current = current.shiftRight((int)consecutiveDivisions);
                    operations -= consecutiveDivisions;
                }
            }
        }
        
        return current;
    }
    
    /**
     * 计算BigInteger末尾有多少个0(即可以被2整除多少次)减少上下文额外开销 将主循环20次除以二循环变成主循环一次辅助循环20次,减少其他判断逻辑19次
     */
    private static long countTrailingZeros(BigInteger n) {
        if (n.equals(BigInteger.ZERO)) return 0;
        
        long count = 0;
        BigInteger temp = n;
        while (temp.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
            temp = temp.divide(BigInteger.valueOf(2));
            count++;
            // 限制最大连续除法次数,避免无限循环
            if (count > 60) break;
        }
        return count;
    }
    
    /**
     * 处理从1开始的循环:1->4->2->1
     */
    private static BigInteger handleCycle(long operations) {
        long remainder = operations % 3;
        if (remainder == 0) return BigInteger.ONE;
        if (remainder == 1) return BigInteger.valueOf(4);
        return BigInteger.valueOf(2);
    }
    
    /**
     * 处理从2开始的循环:2->1->4->2
     */
    private static BigInteger handleCycleFrom2(long operations) {
        long remainder = operations % 3;
        if (remainder == 0) return BigInteger.valueOf(2);
        if (remainder == 1) return BigInteger.ONE;
        return BigInteger.valueOf(4);
    }
    
    /**
     * 处理从4开始的循环:4->2->1->4
     */
    private static BigInteger handleCycleFrom4(long operations) {
        long remainder = operations % 3;
        if (remainder == 0) return BigInteger.valueOf(4);
        if (remainder == 1) return BigInteger.valueOf(2);
        return BigInteger.ONE;
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        // 读取输入
        BigInteger n = new BigInteger(st.nextToken());
        long k = Long.parseLong(st.nextToken());
        
        // 计算结果
        BigInteger result = solve(n, k);
        
        // 输出结果
        System.out.println(result.toString());
        
        br.close();
    }
}