华为OD题目: 完美走位

完美走位

完美走位

解题思路:
遍历输入字符串,统计每个字符(W、A、S、D)出现的次数。
使用滑动窗口方法,从左到右遍历字符串,根据当前窗口内字符的数量计算需要替换的字符数量
如果当前窗口内字符可以通过替换达到平衡,则尝试更新最小长度。

/**

  • 获得完美走位
  • 时间限制: 1s 空间限制: 256MB 限定语言: 不限
  • 题目描述:
  • 在第一人称射击游戏中,玩家通过键盘的A、S、D、W四个按键控制游戏人物分别向左、向后、向右、向前进行移动、从而完成走位。
  • 假设玩家每按动一次键盘,游戏人物会向某个方向移动一步,如果玩家在操作一定次数的键盘并且各个方向的步数相同时,此时游戏人物必定会回到原点,则称此次走位为完美走位。
  • 现给定玩家的走位(例如:ASDA)请通过更换其中一段连续走位的方式使得原走位能够变成一个完美走位。其中待更换的连续走位可以是相同长度的任何走位。
  • 请返回待更换的连续走位的最小可能长度
  • 若果原走位本身是一个完美走位,则返回0。
  • 输入描述
  • 输入为由键盘字母表示的走位s,例如:ASDA
  • 输出描述:
  • 输出为待更换的连续走位的最小可能长度
  • 补充说明:
  • 1、走位长度1 <=s.length <= 10^5
  • 2、s.length 是4的倍数
  • 3、s 中只含有’A,S,D,w 四种字符
  • 示例1
  • 输入:
  • ASDW
  • 输出:
  • 0
  • 说明:
  • 已经是完美走位了
  • 示例2
  • 输入:
  • AASW
  • 输出:
  • 1
  • 说明:
  • 需要把一个A更换成D,这样可以得到“ADSW”或者“DASW”
  • 示例3
  • 输入:
  • AAAA
  • 输出:
  • 3
  • 说明:
  • 可以替换后3个A,得到ASDW。
    */

package com.sf.ccmas.video.config.odd.od13;

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

/**
 * 完美走位
 * 解题思路
 * 遍历输入字符串,统计每个字符(W、A、S、D)出现的次数。
 * 使用滑动窗口方法,从左到右遍历字符串,根据当前窗口内字符的数量计算需要替换的字符数量。
 * 如果当前窗口内字符可以通过替换达到平衡,则尝试更新最小长度。
 */
public class Main7 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String inputStr = in.nextLine();

        Map<Character, Integer> charCountMap = new HashMap<>();
        // 计算输入字符串中每个字符的数量
        char[] charArray = inputStr.toCharArray();
        for (char charName : charArray) {
            charCountMap.put(charName, charCountMap.getOrDefault(charName, 0) + 1);
        }
        int totalLength = charArray.length;
        int avg = totalLength / 4;
        if (avg == charCountMap.get('A') && avg == charCountMap.get('D')
                && avg == charCountMap.get('s') && avg == charCountMap.get('W')) {
            System.out.println(0);
            return;
        }
        int minCount = totalLength;
        //下面使用双指针的来进行逐个遍历
        int left = 0;
        int right = 0;
        //初始化,先从第一个开始,指针right 指向0
        charCountMap.put(charArray[0], charCountMap.get(charArray[0]) - 1);
        while (left < charArray.length) {
            //窗口长度
            int len = right - left + 1;
            int needCount = getMaxCharCount(charCountMap);
            //窗口长度减去需要的字符数
            int val = len - needCount;
            //如果窗口减去需要的长度必须 >= 0,而且差值必须是4的倍数才行,如果差值是3,那也不行因为变换窗口的字符,把整个字符无法变成完全走位
            //下面要注意顺序,左指针是先将map对应的charArray[left] 值 +1,然后left指针右移, 右指针是先移动指针,在减去char的数量
            if (val >= 0 && val % 4 == 0) {
                minCount = Math.min(minCount, len);
                //如果最小的变动数量是1,不会有再小的了,直接退出
                if (minCount == 1) {
                    break;
                }
                charCountMap.put(charArray[left], charCountMap.get(charArray[left])  + 1);
                left++;
            }else {
                right++;
                if (right >= charArray.length) {
                    break;
                }
                charCountMap.put(charArray[right], charCountMap.get(charArray[right]) - 1);

            }

        }
        System.out.println(minCount);

    }

    /**
     * 获取 到达完全走位至少需要的字母数量,
     * 具体步骤如下:
     * 1: 先获取map里最大的一个字符数量
     * 2: 用最大的字符数量 * 4 再减去map里各个里字符的数量, 比如  A AAA, 窗口长度是是1,只有一个A, 剩下3个A
     * 最大字符数是3 那么起码需要 3*4-3-0-0=9个数的窗口长度来填,才能保证完全走位
     * 如果是AA AA ,左边的窗口是2, 右边最大char num是2, 对应: 2*4-2-0-0 = 6,6个数的窗口
     * 如果是AAA A, 左边的窗口是3, 右边最大char num是1, 对应: 1*4- 1-0-0-0, 正好3个数的窗口
     *
     * @param charCountMap
     * @return 返回到达完全走位至少需要的字母数量
     */
    public static int getMaxCharCount(Map<Character, Integer> charCountMap) {
        int max = 0;
        for (char charName : charCountMap.keySet()) {
            max = Math.max(max, charCountMap.getOrDefault(charName,  0));
        }
        Integer aCount = charCountMap.getOrDefault('A', 0);
        Integer dCount = charCountMap.getOrDefault('D', 0);
        Integer sCount = charCountMap.getOrDefault('S', 0);
        Integer wCount = charCountMap.getOrDefault('W', 0);
        int needCount = max * 4 - aCount - dCount - sCount - wCount;
        return needCount;
    }
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值