题解

题目描述

在第一人称射击游戏中,玩家通过键盘的 A、S、D、W 四个按键控制游戏人物分别向左、向后、向右、向前进行移动,从而完成走位。

假设玩家每按动一次键盘,游戏任务会向某个方向移动一步。如果玩家操作一定次数的键盘后,各个方向的步数相同,此时游戏任务必定会回到原点,则称此次走位为完美走位。

现给定玩家的走位(例如:ASDA),请通过更换其中一段连续走位的方式,使得原走位能够变成一个完美走位。其中待更换的连续走位可以是相同长度的任何走位。

请返回待更换的连续走位的最小可能长度。
如果原走位本身是一个完美走位,则返回 0。

思路

要使走位成为完美走位,各个方向的步数必须相同。假设走位长度为 n,由于 n 是 4 的倍数,每个方向的目标步数为 n/4。

  1. 统计当前各方向的步数:
    统计 A,S,D,W 各自的出现次数。
  2. 判断是否已经是完美走位:
    如果所有方向的步数都等于 n/4,则返回 0。
  3. 计算需要调整的步数:
    对于每个方向,计算超出目标步数的部分(即需要减少的步数)。
  4. 使用滑动窗口寻找最小替换区间:
  5. 使用双指针(滑动窗口)从字符串左端开始,逐步扩大右端。
  6. 在窗口内,减少相应方向的超出步数。
  7. 当所有超出步数均被窗口覆盖(即窗口内的字符可以替换为所需的方向),记录窗口长度并尝试缩小窗口以找到最小长度。

代码分析

  1. 统计各方向的步数:遍历字符串,统计 A,S,D,W 的数量。
  2. 计算多余步数:对于每个方向,计算当前步数与目标步数 n/4 的差,如果大于 0,则记录为多余步数。
  3. 滑动窗口:
  4. 初始化左指针为 0,右指针遍历整个字符串。
  5. 在每次移动右指针时,若当前字符是多余的方向,则减少相应的多余步数。
  6. 当所有多余步数均被窗口覆盖时,尝试移动左指针以缩小窗口,直到不满足条件为止。
  7. 记录所有满足条件的窗口长度,取最小值。

python

import sys
from collections import defaultdict

def main():
    s = sys.stdin.read().strip()
    n = len(s)
    target = n // 4
    count = defaultdict(int)
    for c in s:
        count[c] += 1
    
    # 计算多余的步数
    surplus = {}
    for c in 'ASDW':
        if count[c] > target:
            surplus[c] = count[c] - target
    
    # 如果没有多余步数,则已经是完美走位
    if not surplus:
        print(0)
        return
    
    min_len = n
    window = defaultdict(int)
    left = 0
    formed = 0
    required = len(surplus)
    
    for right in range(n):
        c = s[right]
        if c in surplus:
            window[c] += 1
            if window[c] == surplus[c]:
                formed += 1
        
        while formed == required:
            min_len = min(min_len, right - left + 1)
            d = s[left]
            if d in surplus:
                window[d] -= 1
                if window[d] < surplus[d]:
                    formed -= 1
            left += 1
    
    print(min_len)

if __name__ == "__main__":
    main()

java

import java.util.*;
public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int n = s.length();
        int target = n / 4;
        Map<Character, Integer> count = new HashMap<>();
        for(char c : s.toCharArray()){
            count.put(c, count.getOrDefault(c, 0) + 1);
        }
        
        // 计算多余的步数
        Map<Character, Integer> surplus = new HashMap<>();
        for(char c : new char[]{'A','S','D','W'}){
            if(count.getOrDefault(c, 0) > target){
                surplus.put(c, count.get(c) - target);
            }
        }
        
        // 如果没有多余步数,则已经是完美走位
        if(surplus.isEmpty()){
            System.out.println(0);
            return;
        }
        
        int minLen = n;
        Map<Character, Integer> window = new HashMap<>();
        int left = 0;
        int formed = 0;
        int required = surplus.size();
        
        for(int right = 0; right < n; right++){
            char c = s.charAt(right);
            if(surplus.containsKey(c)){
                window.put(c, window.getOrDefault(c, 0) + 1);
                if(window.get(c).intValue() == surplus.get(c).intValue()){
                    formed++;
                }
            }
            
            while(formed == required){
                minLen = Math.min(minLen, right - left + 1);
                char d = s.charAt(left);
                if(surplus.containsKey(d)){
                    window.put(d, window.get(d) - 1);
                    if(window.get(d) < surplus.get(d)){
                        formed--;
                    }
                }
                left++;
            }
        }
        
        System.out.println(minLen);
    }
}

cpp

#include <bits/stdc++.h>
using namespace std;

int main(){
    string s;
    cin >> s;
    int n = s.length();
    int target = n / 4;
    unordered_map<char, int> count;
    for(char c : s) count[c]++;
    
    // 计算多余的步数
    unordered_map<char, int> surplus;
    for(auto &[k, v] : count){
        if(v > target){
            surplus[k] = v - target;
        }
    }
    
    // 如果没有多余步数,则已经是完美走位
    if(surplus.empty()){
        cout << 0;
        return 0;
    }
    
    // 使用滑动窗口寻找最小长度
    int minLen = n;
    unordered_map<char, int> window;
    int left = 0;
    int required = surplus.size();
    int formed = 0;
    
    for(int right = 0; right < n; right++){
        char c = s[right];
        if(surplus.find(c) != surplus.end()){
            window[c]++;
            if(window[c] == surplus[c]){
                formed++;
            }
        }
        
        // 当所有多余的方向都在窗口中被覆盖
        while(formed == required){
            minLen = min(minLen, right - left + 1);
            char d = s[left];
            if(surplus.find(d) != surplus.end()){
                window[d]--;
                if(window[d] < surplus[d]){
                    formed--;
                }
            }
            left++;
        }
    }
    
    cout << minLen;
}


灵芸小骏
8.6k 声望728 粉丝

移动开发者。