#P2717. 第2题-字符串移动
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 45
            Accepted: 14
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年3月20日-阿里云(开发岗)
                              
                      
          
 
- 
                        算法标签>前缀和          
 
第2题-字符串移动
题解
题面描述
给定一个长度为n的字符串s(s仅包含字符′<′和′>′),其中字符′<′代表向左移动,′>′代表向右移动。对于每个起始位置i(0≤i<n),小红按照顺序依次执行si,si+1,si+2,…中的指令,但不必执行到字符串末尾。要求判断是否存在某个非空前缀,使得执行后小红能够回到原点(即净位移为0)。对于每个i,输出1表示存在这种可能,输出0表示不存在。
思路
令每个字符对应的移动量为:
- aj=+1 当s[j]=′>′
 - aj=−1 当s[j]=′<′
 
设定义前缀和数组P满足
P[0]=0,P[k]=a0+a1+⋯+ak−1(1≤k≤n)
从起点i出发,执行L个指令后的位移为
P[i+L]−P[i]因此要求存在L≥1使得
P[i+L]−P[i]=0⟺ P[i+L]=P[i]
换句话说,对于每个i,如果在区间[i+1,n]内存在某个位置k使得P[k]=P[i],则答案为1,否则为0。
一种简单高效的方法是预处理整个P数组,并统计每个值最后出现的位置。对于每个i(对应P[i]),若该值最后出现的位置大于i,则说明后续至少存在一个位置使得前后前缀和相等。
C++
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    string s;
    cin >> s;
    
    // 计算前缀和,P[0]=0, P[i+1]=P[i]+(s[i]=='>'? 1 : -1)
    vector<int> P(n+1, 0);
    for (int i = 0; i < n; i++){
        P[i+1] = P[i] + (s[i] == '>' ? 1 : -1);
    }
    
    // 记录每个前缀和最后出现的位置
    unordered_map<int,int> lastPos;
    for (int i = 0; i <= n; i++){
        lastPos[P[i]] = i; // 每次覆盖即为最后出现位置
    }
    
    // 对于每个起始位置 i, 判断是否存在 k (i+1 <= k <= n) 使得 P[k]==P[i]
    for (int i = 0; i < n; i++){
        if (lastPos[P[i]] > i)
            cout << 1 << " ";
        else
            cout << 0 << " ";
    }
    
    return 0;
}
Python
# -*- coding: utf-8 -*-
# 读入数据
n = int(input().strip())
s = input().strip()
# 计算前缀和, P[0] = 0, P[i+1] = P[i] + (1 if s[i]=='>' else -1)
P = [0]*(n+1)
for i in range(n):
    P[i+1] = P[i] + (1 if s[i]=='>' else -1)
# 记录每个前缀和最后出现的位置
lastPos = {}
for i in range(n+1):
    lastPos[P[i]] = i  # 每次覆盖为最后一次出现
# 对于每个起始位置 i, 判断是否存在 k (i+1 <= k <= n) 使得 P[k] == P[i]
res = []
for i in range(n):
    if lastPos[P[i]] > i:
        res.append("1")
    else:
        res.append("0")
        
print(" ".join(res))
Java 解法
import java.util.*;
import java.io.*;
public class Main {
    public static void main(String[] args) throws IOException {
        // 使用 BufferedReader 加速输入
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine().trim());
        String s = br.readLine().trim();
        
        // 计算前缀和, P[0] = 0, P[i+1] = P[i] + (s.charAt(i)=='>'? 1 : -1)
        int[] P = new int[n+1];
        for (int i = 0; i < n; i++) {
            P[i+1] = P[i] + (s.charAt(i) == '>' ? 1 : -1);
        }
        
        // 使用 HashMap 记录每个前缀和最后出现的位置
        HashMap<Integer, Integer> lastPos = new HashMap<>();
        for (int i = 0; i <= n; i++) {
            lastPos.put(P[i], i); // 每次put覆盖即为最后出现位置
        }
        
        // 对于每个起始位置 i, 判断是否存在 k (i+1 <= k <= n) 使得 P[k] == P[i]
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            if (lastPos.get(P[i]) > i)
                sb.append("1 ");
            else
                sb.append("0 ");
        }
        
        System.out.println(sb.toString().trim());
    }
}
        题目内容
小红在一维度的世界中,她可以向左或者向右移动。她拿到一个长度为n的字符串s,仅包含'<'和'>' 两种字符,'<' 表示向左移动,'>'表示向右移动。
小红想知道,如果从字符串s的第i(0≤i<n)个字符开始,然后按照Si,Si+1,Si+2,...的顺序依次移动,那么小红有没有机会回到原地。
值得注意的是,你需要对于任意的i(0≤i<n) 都判断是否存在一种移动方式,使得小红可以回到原地且不一定需要执行到sn−1,每个i的判断互不影响。
输入描述
第一行一个整数n(1≤n≤2×105),表示字符串s的长度。
第二行一个字符串s,仅包含'<'和'>'两种字符。
输出描述
输出n个整数,第i个整数表示从第i个字符开始移动,小红有没有机会回到原地,若有机会输出1,否则输出0。
样例1
输入
4
><><
输出
1 1 1 0