首页 > 试题广场 >

字母交换

[编程题]字母交换
  • 热度指数:5137 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

【编码题】字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?



输入描述:
第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)


输出描述:
一个非负整数,表示操作之后,连续最长的相同字母数量。
示例1

输入

abcbaa 2

输出

2

说明

使2个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。
所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。 
//头像 //
#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
using namespace std;

string str;
int m;

int cnt(const vector<int>& vec) {
    int n = vec.size();
    vector< vector<int> > dp(n, vector<int>(n, 0));
    for(int i=0; i<n-1; ++i) {
        dp[i][i+1] = abs(vec[i+1] - vec[i]) - 1;
    }
    for(int j=2; j<n; ++j) {
        for(int i=0; i<n-j; ++i) {
            int row = i, col = i+j;
            dp[row][col] = dp[row+1][col-1] + abs(vec[col] - vec[row]) - (col-row);
        }
    }
    int Max = 0;
    for(int i=0; i<n; ++i) {
        for(int j=i; j<n; ++j) {
            if (dp[i][j] <= m) {
                Max = max(Max, j-i+1);
            }
        }
    }
    return  Max;
}


int main()
{
    cin >> str >> m;
    vector< vector<int> > vec(26);
    for(int i=0; i<str.size(); ++i) {
        vec[str[i]-'a'].push_back(i);
    }
    int Max = 0;
    for(int k=0; k<26; ++k) {
        Max = max(Max, cnt(vec[k]));
    }
    cout << Max << endl;
    return 0;
}
/*
lufhkcyqnnheshcogbovclcxrfneppkxdvolqtstdkmgsscvfvnnigltgyardkfvavrrwbblzcxzwmteonksiaswfvfsgpxwosev 200
hkdbqojqvxlfulshrhpysezhlyzolb 20
ooxnwetkuvpqjuabmovhkpypxbgpxzemuupqvavonyfscmkrvsvixcejdrutwwfndzkdxbrwgptievanpqfzlprwyqupidspcgrw 200
*/
动态规划状态转移方程dp[i][j] = dp[i+1][j-1] + abs(vec[j] - vec[i]) - (j-i); dp[i][j]第i个数到第j个数移动的次数

编辑于 2018-03-05 22:30:08 回复(3)
def cal(p,m):
    dp = [[0 for i in range(len(p))] for j in range(len(p))]
    for i in range(0,len(p)-1):
        dp[i][i+1] = p[i+1]-p[i]-1
    for le in range(2,len(p)):
        for i in range(0,len(p)-le):
            j = i+le
            dp[i][j] = dp[i+1][j-1]+(p[j]-p[i])-(j-i)
    res = 0
    for i in range(len(p)):
        for j in range(i,len(p)):
            if dp[i][j]<=m:
                res = max(res,j-i+1)
    return res

inp = input().split()
s,m = inp[0],int(inp[1])
positions = [[] for i in range(26)]
for i in range(len(s)):
    positions[ord(s[i])-ord('a')].append(i)
res = 0
for i in range(26):
    res = max(res,cal(positions[i],m))
print(res)

发表于 2019-02-16 10:25:40 回复(1)
区间dp
dp[i][k] = dp[i+1][k-1] + pos[i+1] - pos[i] - 1 + pos[k] - pos[k-1] - 1 + pos[k-1] - pos[i+1] + 1 - (k - i - 1)
= dp[i+1][k-1] + pos[k] - pos[i] - 1 - (k - i - 1)
= dp[i+1][k-1] + pos[k] - pos[i] + 1 - lens
while True:
    try:
        line = input().split()
        s = list(line[0])
        n = int(line[1])
        # 将字符去重复
        ss = set(s)
        maxsub = 1
        for i in ss:
            # 记录字符出现的位置
            pos = []
            for j in range(len(s)):
                if s[j] == i:
                    pos.append(j)
            ll = len(pos)
            if ll < maxsub:
                continue
            temp = 1
            dp = [[1 for _ in range(ll)] for _ in range(ll)]
            for lens in range(2,ll+1):
                for j in range(ll+1-lens):
                    k = j + lens - 1
                    dp[j][k] = dp[j+1][k-1] + pos[k] - pos[j] + 1 - lens
                    if dp[j][k] <= n:
                        temp = lens
            maxsub = max(maxsub, temp)
        print(maxsub)
    except:
        break

编辑于 2021-03-12 18:12:58 回复(0)
贴个golang的吧,插入代码选项都没golang,go什么时候才能站起来。
package main

import (
    "fmt"
)

func main(){
    var s string
    var m int64
    fmt.Scan(&s, &m)
    arrs := [26][]int64{}
    for i, chr := range s {
        arrs[int32(chr) - 'a'] = append(arrs[int32(chr) - 'a'], int64(i))
    }
    
    var ans int64
    for _, arr := range arrs {
        n := len(arr)
        if  int64(n) <= ans {
            continue
        }
        dp := make([][]int64, n)
        for i := 0; i < n;i++  {
            dp[i] = make([]int64, n)
        }
        for i := n - 1; i >= 0; i-- {
            for j := i + 1; j < n; j++ {
                if j == i + 1 {
                    
                   dp[i][j] = arr[j] - arr[i] - 1
                }else {
                    //dp[i][j] = dp[i + 1][j - 1] + arr[j] - arr[i] - 1 - (j - i - 1) 
                    dp[i][j] = dp[i + 1][j - 1] + arr[j] - arr[i]  - int64(j) + int64(i)
                }
                if dp[i][j] <= m {
                    if int64(j - i + 1) > ans {
                        ans = int64(j - i + 1)
                    }
                }
            }
        }
    }
    fmt.Println(ans)
}


发表于 2021-01-24 20:03:11 回复(0)
#include <bits/stdc++.h>
using namespace std;

bool F(vector<vector<int>> &v, int n, int m){
    bool flag = false;
    for(int i=0;i<v.size();i++){
        if(v[i].size() < n)
            continue;
        for(int j=0;j<v[i].size();j++){
            if(j+n > v[i].size())
                break;
            int s = 0, t = j+n/2;
            for(int k=j;k<j+n;k++){
                if(k<=t)
                    s += (v[i][t] - (t-k) - v[i][k]);
                else
                    s += (v[i][k] - v[i][t] - (k-t));
            }
            if(s <= m)
                flag = true;
        }
    }
    return flag;
}

int main(){
    string s;
    int m, cnt=0;
    cin>>s;
    scanf("%d", &m);
    map<char, int> mp;
    for(auto &c: s)
        mp[c] = cnt++;
    vector<vector<int>> v;
    for(int i=0;i<cnt;i++){
        vector<int> t;
        v.push_back(t);
    }
    for(int i=0;i<s.size();i++)
        v[mp[s[i]]].push_back(i);
    int l=0, r=s.size()+1;
    while(l<r){
        int k = (l+r)>>1;
        if(F(v, k, m))
            l = k+1;
        else
            r = k;
    }
    if(l==0)
        puts("0");
    else
        printf("%d\n", l-1);
    return 0;
}

发表于 2020-12-13 17:58:51 回复(0)

参考评论区大佬的答案,自己还需要多练习,多思考
public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		String str=sc.nextLine();
		String s=str.split(" ")[0]; 	//用于接收待处理的字符串
		int m=Integer.parseInt(str.split(" ")[1]);	//用来接收处理字符串的的次数m
		int res=0;
		
		//建立列表,装接收置,待处理的是26个字母a-z,每接收一个字母都要建立相应的ArrayList
		for(char ch='a';ch<='z';ch++) {
			ArrayList<Integer> positions=new ArrayList<Integer>();
			for(int i=0;i<s.length();i++) {
				if(ch==s.charAt(i)) {	//键盘接收来的字符刚好与ch表示的字符相同,则为键盘接收来的字符添加下标
					positions.add(i);					
				}
			}
			
			//如果只有1个字符或没有则跳出当前循环
			if(positions.size()<2) {
				continue;
			}
			
			
			//建立动态规划dp,一维装字母,另一维装位置,其维度与前面建立的positions的大小相等
			int size=positions.size();
			int dp[][]=new int[size][size];
		
			//dp[i][j]表示,把位置positions[i],,,positions[j]的字母移动到一起所需要的最少移动次数
			for(int j=0;j<size;j++) {
				dp[j][j+1]=positions.get(j+1)-positions.get(j)-1;
			}
			
			//当相同的字母在字符串中多次出现且不连续时,从两边网中间移动,保证移动次数最少。
			for(int len=2;len<size;len++) {
				for(int left=0;left<size-len;left++) {
					int right=left+len;
					dp[left][right]=dp[left+1][right-1]+positions.get(right)-positions.get(left)-1-(right-left-1);
				}
			}
			
			//最后比较
			for(int i=0;i<size;i++) {
				for(int j=i+1;j<size;j++) {
					
					if(dp[i][j]<=m) {
						res=Math.max(res, j-i+1);
					}
				}
			}
		}
		System.out.println(res);
	}


发表于 2020-06-20 18:09:14 回复(1)
这道题的字符串长度在测试中与题中说明的不符,一直报段错误,完全找不到哪里错了,最后随手改了一下字符串的长度,竟然就对了,真的服了。思路比较暴力。
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 10;    // 1e3 + 10一直段错误
char s[maxn];
vector<int> pos[30];

int main() {
	int n, m;
	scanf("%s%d", s, &m);
	n = strlen(s);
	for (int i = 0; i < n; i++) {
		pos[s[i] - 'a'].push_back(i);
	}
	int res = 0;
	for (int i = 0; i < n; i++) {
		int x = s[i] - 'a', left = m, cnt = 1;
		int l = i-1, r = i+1;
		int p = lower_bound(pos[x].begin(), pos[x].end(), i) - pos[x].begin();
		int le = p-1, ri = p+1;
		while (left > 0 && (le >= 0 || ri < pos[x].size())) {
			if (le < 0) {
				left -= pos[x][ri] - r;
				++r;
				++ri;
				++cnt;
			} else if (ri >= pos[x].size()) {
				left -= l - pos[x][le];
				--l;
				--le;
				++cnt;
			} else {
				if (pos[x][ri]-r < l-pos[x][le]) {
					left -= pos[x][ri] - r;
					r++;
					ri++;
					cnt++;
				} else {
					left -= l - pos[x][le];
					l--;
					le--;
					cnt++;
				}
			}
		}
		if (left < 0) cnt--;
		res = max(res, cnt);
	}
	cout << res << endl;
}


发表于 2020-03-22 19:07:51 回复(0)
"""
# 动态规划题。
# 首先题目说只有小写字母,字符的类型的只有26种,为了简化问题我们只要讨论a字符,其他字符只要重复这个过程即可
# 对于a字符,只需要记下他的位置char[c],就是把这些位置转换成连续的最少转换次数,这就可以dp了。
# 设dp[i][j]表示把i到j这一段合在一起最少需要的次数,根据不等式|x−a|+|x−b|a), 可以推导出其状态转移方程为:
# dp[i][j]=dp[i+1][j−1]+char[j]−char[i]−(leng-1)
# 枚举的时候是先枚举小区间然后再枚举大区间。
"""
def exchange(char,m):
    n = len(char)
    ans = 0
    dp = [[0]*n for i in range(n)]
    for i in range(n-1):
        dp[i][i+1] = char[i+1] - char[i] - 1 # 相邻两个的交换的最小次数
        if dp[i][i+1] < m:
            ans = 2
    for leng in range(2,n):
        for i in range(0,n-leng):
            j = leng + i
            dp[i][j] = dp[i+1][j-1] + (char[j]-char[i]) - (j-i-1)
            if dp[i][j] < m:
                ans = leng + 1
    return ans
s, m = input().split()
m = int(m)
char = [[] for _ in range(26)] # 记录字符串中每一字母的位置
for i in range(len(s)):
    char[ord(s[i])-97].append(i)
res = 0
for i in range(26):
    if char[i]:
        res = max(res,exchange(char[i],m))
print(res)
编辑于 2019-04-12 22:04:26 回复(0)
def Count(g,step):
    n = len(g)
    minstep = float('inf')
    dp = [[0 for _ in range(n)] for _ in range(n)]
    if n==1:
        return 1
    #所有2个连续相连所需要的互换次数
    for i in range(n-1):
        dp[i][i+1] = g[i+1]-g[i]-1
        minstep = min(minstep,dp[i][i+1])
    if minstep>step:
        return 1
    elif minstep==step:
        return 2
    else:
        #接着考虑3个连续的所有情况
        for i in range(2,n):
            minstep = float('inf')
            for j in range(n-i):
                row = j
                col = j+i
                # 这里较难理解,假设显现考虑这样一个情况:
                # 12,,,,,,,,56
                #,,,,是中间部分,即dp[row+1][col-1]
                #那么假设中间部分排列好后左面是q,右面是p
                #那么本轮移动12 和56 就共需要q-12-1 和56-p-1
                #化简后就是56-12+q-p-2,假设12和56的坐标是row,col
                #可以得到 col-row-2 = p-q 所以q-p-2 = row-col
                #其中56-12就是g[col]-g[row] 所以56-12+q-p-2 = g[col]-g[row]-(col-row)
                dp[row][col] = dp[row+1][col-1]+g[col]-g[row]-(col-row)
                minstep = min(minstep,dp[row][col])
            if minstep>step:
                return i
            if minstep==step:
                return i+1
    return n

S,m = [e for e in input().split()]
m = int(m)
group = {}

for i,s in enumerate(S):
    if s not in group:
        group[s] = [i]
    else:
        group[s].append(i)
        
result = 0
for key in group.keys():
    result = max(result,Count(group[key],m))
print(result)

发表于 2019-02-11 16:00:10 回复(1)

这一题我觉得作为笔试题,还是有些难度的。
思路是这样的,我们对每一个字母分别求可能连接的成的最大距离。
这时候就需要用26个列表,来分别保存每个字母的出现在原字符串中的位置(代码中v表示)。
我们下面针对一个字母考虑:
dp[i][j]:表示v中第i到第j个位置的字母如果需要移动到在一起,需要移动的次数。
那么转移方程就有了

dp[left][right] = dp[left+1][right-1] + (v[right] - v[left] - 1) - (right - left - 1)

这里做一下说明:
对于最左边位置left和最右边位置right字符串,如果只需要将这俩字符移动在一起,则需要固定的(v[right] - v[left] - 1)次移动,但是这个区间内已经有了移动好的(right - left - 1)个字母,所以可以少移动这么多次,固需要减去这个数字。

s, m = input().split()
m = int(m)

from collections import defaultdict

d = defaultdict(list)

for i,c in enumerate(s):
    d[c].append(i)

res = 0
for k,v in d.items():
    n = len(v)
    dp = [[0] * n for _ in range(n)]
    for i in range(1,n):
        dp[i-1][i] = v[i]-v[i-1]-1
    for k in range(2,n):
        for i in range(n-k):
            left, right = i, k+i
            dp[left][right] = dp[left+1][right-1] + (v[right] - v[left] - 1) - (right - left - 1)

for i in range(n):
    for j in range(i,n):
        if dp[i][j] <= m:
            res = max(res, j-i+1)

print(res)
发表于 2019-07-02 09:34:58 回复(2)
不知道这种题除了刁难人有什么意义
发表于 2020-08-07 21:47:02 回复(0)
完美AC,运行时间57ms。
将数据按字符分开存储在字典中。
对于每一个字符,如果这个key值下数据长度短于目前找到的最大长度,就直接跳过。
否则遍历(目前最大长度,该key值数据长度),寻找是否有符合条件的更优解。
移动数据的时候,所有数据往中间数据靠是最优解。
s, m = input().split()
m = int(m)
s = list(s)
  
arr = {}
for i in range(0,len(s)):
    if s[i] not in arr:
        arr[s[i]] = []
    arr[s[i]].append(i)
      
Max = 0
for i in arr:
    if len(arr[i])>Max:
        for j in range (Max,len(arr[i])):
            Sum = 0
            for k in range(0,j+1):
                Sum += abs(arr[i][(j//2)]-arr[i][k]) - abs((0+j//2)-k)
            if Sum <= m:
                Max = max(Max,j+1)
print(Max)


发表于 2020-03-31 11:50:33 回复(2)
思路很简单,就是相同字母中,选一个字母为中心,计算其他字母向它靠近需要的步数的和,从近到远的顺序去靠近。运行时间:13ms
#include <bits/stdc++.h>
#include <vector>
using namespace std;

vector<int>c[30];//一种字母出现的所有位置记在一个数组

int main() {
    string str;
    int M;
    int ans=1;
    cin >> str >> M;
    //在交换次数m内,使最多连续的位置上的字母相同

    for (int i = 0; i < str.size(); i++) {
        char temp = str[i];
        c[temp - 'a'].push_back(i);
    }

    //选一个字母
    for (int ii = 'a'; ii <= 'z'; ii++) {
        int i = ii - 'a';
        int maxx = c[i].size();
        //选一个中心点 m
        for (int m = 0; m < maxx; m++) {
            int lianXu = 1;//至少连续1(自己)
            int sheng[2] = {1, 1};//靠在一起变长后对于后面的移动就会省距离
            int dire[2] = {m - 1, m + 1};//左右双指针走到的位置
            int have = M;
            while (dire[0] >= 0 || dire[1] < maxx) {
                int index;
                int dist[2];
                if(dire[0] >= 0)
                    dist[0] = c[i][m] - c[i][dire[0]] - sheng[0];
                else 
                    dist[0]=0x3f3f3f3f;

                if(dire[1] < maxx)
                    dist[1] = c[i][dire[1]] - c[i][m] - sheng[1];
                else
                    dist[1]=0x3f3f3f3f;

                index = dist[0] <= dist[1] ? 0 : 1;
                have -= dist[index];
                if (have >= 0) {//还有剩余步数吗?
                    dire[index]=index==0?dire[index]-1:dire[index]+1;
                    sheng[index]++;
                    lianXu++;
                } else {
                    break;
                }
            }
            ans=max(ans,lianXu);
            lianXu=1;
        }
    }
    cout<<ans;

}


发表于 2023-03-17 10:59:06 回复(0)
平庸如我,没想出来。
发表于 2022-07-17 12:18:37 回复(0)
关键的一点:经过交换后,几个相同的字母连在一块的的最优解,一定是交换前和交换后各个字母的相对顺序不变。
发表于 2022-05-18 18:42:24 回复(0)
这题用动态规划就是简单问题强行复杂化。题目本质是L1正则化求解或者说是绝对值函数最优化,是的没有看错,和动态规划没关系,因为最优中心点可能是任意位置,而非必需固定某个字符不动移动其他,因此用双向队列递归,高效省内存。
#include <iostream>
#include <vector>
#include <cmath>
#include <deque>
using namespace std;


int max_move(deque<int>& x, int m){
    int len = x.size();
    int med, total = 0;
    if(len % 2 == 1){
        // med -> median
        med = x[len/2];
        for(int pos=0; pos<len; pos++)
            total += abs(x[pos] - med) - abs(len/2 - pos);
    }
    else{
        // as for even, center&nbs***bsp;median maybe a float, nevermind,
        // you can also write med as (x[len/2] + x[len/2-1])/2 + 1
        total += len/2; med = (x[len/2] + x[len/2-1])/2;
        for(int pos=0; pos<len; pos++)
            total += abs(x[pos] - (x[len/2] + x[len/2-1])/2) - abs(len/2 - pos);
    }
    //now total is optimized solution to aggregate all of a certain char
    if(total <= m) return len;
    else{
        // discard the most biased value technically: head&nbs***bsp;tail
        abs(x.front() - med) >= abs(x.back() - med) ? x.pop_front(): x.pop_back();
        return max_move(x, m);
    }
}
int main(){
    vector<deque<int> > str(26);
    string temp; int m; cin >> temp >> m;
    int result = 0;
    for(int i=0; i<temp.size(); i++)
        str[temp[i]-'a'].push_back(i);
    for(int i=0; i<26; i++){
        if(!str[i].empty())
            result = max(result, max_move(str[i], m));
    }
    cout << result << endl;
    return 0;
}

发表于 2021-05-08 18:46:42 回复(0)
import java.util.*;

public class Main{
    static int res = 1;
    public static void main(String[] args){
        
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        String str = input.split(" ")[0];
        int m = Integer.parseInt(input.split(" ")[1]);
        
        HashMap<Character, List<Integer>> map = new HashMap<>();
        char[] chars = str.toCharArray();
        int len = chars.length;
        
        for(int i = 0; i < len; i++){
            List<Integer> list = map.getOrDefault(chars[i], new ArrayList<>());
            list.add(i);
            map.put(chars[i], list);
        }
        
        for(int i = 0; i < len; i++){
            char c = chars[i];
            List<Integer> list = map.get(c);
            moveTogether(list, i, m);
            /*
            int lessCount = 0;
            for(int num : list){
                if(num < i){
                    lessCount++;
                }
                else{
                    break;
                }
            }
            int greatCount = list.size()-1-lessCount;
            for(int j = 0; j < lessCount; i++){
                int cur = list.get(j);

                // 现在这个节点的位置在cur,要移动到          (0 1 j 3 4 ... lessCount-1)i
                // lesscount-2的时候对应i-2
                // lesscount-1的时候对应i-1
                int target = i + j - lessCount;
                int times = 
            }
        }
*/
        
        
        
    }
                System.out.println(res);
        
  
    
        
    }
            // 在times步内,尽可能把list里面的数字移动到mid周围
        public static void moveTogether(List<Integer> list, int mid, int times){
            int len = list.size();
            int mid_index = 0;
            for(int i = 0; i < len; i++){
                if(list.get(i) == mid){
                    mid_index = i;
                    break;
                }
            }
            int left_index = mid_index-1;
            int right_index = mid_index+1;
            int count = 1;
            // mid为中心的左右边界
            int left_mid = mid-1;
            int right_mid = mid+1;
            while(times > 0){
                if(left_index < 0 && right_index >= len){
                    break;
                }
                
                // 看一下左边和右边哪个更近一点
                int left_dist;
                if(left_index < 0)    
                    left_dist = Integer.MAX_VALUE / 2;
                else    
                    left_dist = left_mid - list.get(left_index);
                int right_dist;
                if(right_index >= len)   {
                    right_dist = Integer.MAX_VALUE / 2;
                } 
                else {
                    right_dist = list.get(right_index) - right_mid; 
                }    
                   
                if(left_dist > right_dist){
                    // 右边靠更加近一点
                    if(times < right_dist)    break;
                    times -= right_dist;
                    right_mid++;
                    count++;
                    right_index++;
                }
                else{
                    if(times < left_dist)    break;
                    times -= left_dist;
                    left_mid--;
                    left_index--;
                    count++;
                }
            }
            res = Math.max(count, res);
        }
  
}

发表于 2021-01-18 21:20:46 回复(0)
using System;
using System.Collections.Generic;

namespace CSExercise
{
    class Program
    {
        static int maxTurn;
        static Dictionary<char, List<int>> dict;
        
        static int MaxLength(List<int> list)
        {
            if (list.Count == 0) return 0;

            List<int> sortedList = new List<int>();

            int centerIndex = list.Count / 2;
            int moveToIndex = list[centerIndex];
            
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = Math.Abs(moveToIndex - list[i]) - Math.Abs(centerIndex - i);
            }

            list.Sort();
            int result = 0;
            int turn = maxTurn;
            foreach (int item in list)
            {
                if (item > turn)
                {
                    break;
                }
                result++;
                turn -= item;
            }
            return result;
        }
        
        static void Main(string[] args)
        {
            dict = new Dictionary<char, List<int>>();
            string[] str = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);
            string original = str[0];
            maxTurn = int.Parse(str[1]);
            for (int i = 0; i < original.Length; i++)
            {
                if (dict.TryGetValue(original[i], out List<int> list))
                {
                    list.Add(i);
                }
                else
                {
                    List<int> l = new List<int>();
                    l.Add(i);
                    dict.Add(original[i], l);
                }
            }

            int maxLength = 0;
            foreach (var item in dict)
            {
                maxLength = Math.Max(maxLength, MaxLength(item.Value));
            }
            Console.WriteLine(maxLength);
        }
    }
}

发表于 2020-09-03 16:37:24 回复(0)
import java.util.*;
public class Main
{
    private static int m;
    private static int res=0;
    private static Map<Character,ArrayList<Integer>> mymap=new TreeMap<>();
    public static void main(String []args)
    {
        Scanner cin=new Scanner(System.in);
        String s=cin.next();
        m=cin.nextInt();
        for(int i=0;i<s.length();i++)
        {
            char c=s.charAt(i);
            if(mymap.containsKey(c))
            {
                ArrayList<Integer> list=mymap.get(c);
                list.add(i);
                mymap.put(c,list);
            }
            else
            {
                ArrayList<Integer> list=new ArrayList<Integer>();
                list.add(i);
                mymap.put(c,list);
            }
        }
        execute();
        System.out.print(res);
    }
     public static void execute()
     {
          for(char c:mymap.keySet())
          {
              ArrayList<Integer> list=mymap.get(c);
              int n=list.size();
              int [][]dp=new int[n][n];
              for(int l=2;l<=n;l++)
                  for(int left=0;left+l<=n;left++)
                  {
                      dp[left][left+l-1]=dp[left+1][left+l-2]+list.get(left+l-1)-list.get(left)-1-(l-2);
                      if(dp[left][left+l-1]<=m)
                      {
                          res=Math.max(res,l);
                      }
                  }
          }
     }
}

发表于 2020-06-30 16:32:45 回复(0)
参考大佬们的答案写了一下。基本没变
	 public static void main(String[] args){
	        Scanner in = new Scanner(System.in);
	        int res = 1;
	        String str = in.nextLine();
	        String s = str.split(" ")[0];
	        int m = Integer.parseInt(str.split(" ")[1]);
	        for(char ch = 'a'; ch <= 'z'; ch++){
	            ArrayList<Integer> indexal = new ArrayList<>();
	            for(int i = 0; i < s.length(); i++){
	                if(ch == s.charAt(i)){
	                    //添加下标
	                    indexal.add(i);
	                }
	            }
	            if(indexal.size() < 2){
	                //只有一个连续字符或没有
	                continue;
	            }
	            int size = indexal.size();
	            int[][] dp = new int[size][size];
	            for(int j = 1; j < size; j++){
	                dp[j-1][j] = indexal.get(j) - indexal.get(j-1) - 1;
	            }
	            //区间大小从2到size,至少三个字符
	            
	            for(int length = 2; length < size; length++){
	                for(int left = 0; left < size - length; left++){
	                    int right = left + length ;
	                    //例如
	                    //abcdaadegca
	                    //对于a来说
	                    //indexal中存放的index: 0 5 6 11
	                    //遍历0-2,1-3 等区间
	                    dp[left][right] = dp[left + 1][right- 1] + indexal.get(right) - indexal.get(left) - 1 -(right - left -1);   
	                    //m次操作内可以完成
	                    if(dp[left][right] <= m){
	                        res = Math.max(res,right - left + 1);
	                    }
	                }
	            }
	        }
	        System.out.println(res);
	 

	}	


编辑于 2019-11-26 18:17:05 回复(1)