[英]Find minimum length of substring to rearrange for palindromic string
有一個字符串 s。 substring 的最小長度是多少,以重新排列以制作字符串的回文。
例子:
輸入: abbaabbca
Output: 4
我可以重新排列 substring 從索引4 到 7 (abbc) ,並得到abbacabba
保證重排后有回文。
有沒有辦法通過修改 Manacher 或其他一些文本算法來解決它?
謝謝。
我認為標准文本處理算法並非如此。 它是如此簡單,您不需要它們 - 字符串只有一個重新洗牌的部分,因此可能會出現四種情況。
'ppssXXXXXXXpp'
'ppXXXXXsssspp'
'ppsssiiiXXXpp'
'ppXXXiiissspp'
在哪里
我們可以先檢查和剪輯外部回文部分,留下'ssXXXXXXX'
、 'XXXXXssss'
、 'sssiiiXXX'
或'XXXiiisss'
然后我們使用對稱性——如果中間部分存在,我們可以任意選擇我們保留哪一邊,哪一邊洗牌以適應另一邊,所以我們只做一個。 當沒有中間回文部分時,我們簡單地運行相同的檢查,但從相反的方向開始,然后我們選擇給出較短 substring 的那個
所以,讓我們從頭開始。 我們將簡單地在另一個字符之后取一個字符's--------'
'ss-------'
'sss------'
並在字符串的 rest 不再與 rest 匹配時停止。
什么時候發生? 當字符串的 'ssss... 部分已經吞噬了超過一半的字符出現時,那么它將在另一側丟失並且無法通過改組來匹配。
另一方面,在通過字符串的中間之后,我們總是會吃掉超過一半的每個字符的出現次數。 所以會出現三種情況。
'sssXXXXXXXXXXXX'
'ssssiiiiXXXX'
生成的算法(在 java 中,已經在這里嘗試過):
package palindrometest;
import java.io.*;
import java.util.*;
import java.util.stream.*;
class PalindromeTest {
static int[] findReshuffleRange( String s ) {
// first the easy part,
//split away the already palindromatic start and end if there is any
int lo = 0, hi = s.length()-1;
while(true) {
if( lo >= hi ) {
return new int[]{0,0}; // entire string a palindrome
}
if( s.charAt(lo) != s.charAt(hi) ) {
break;
}
lo++;
hi--;
}
// now we compute the char counts and things based on them
Map<Character,Integer> charCounts = countChars( s, lo, hi );
if( !palindromePossible( charCounts ) ) {
return null;
}
Map<Character,Integer> halfCounts = halfValues( charCounts );
char middleChar = 0;
if( (s.length() % 2) != 0 ) { // only an odd-sized string has a middle char
middleChar = findMiddleChar( charCounts );
}
// try from the beginning first
int fromStart[] = new int[2];
if( findMiddlePart( fromStart, s, lo, hi, halfCounts, middleChar, false ) ) {
// if the middle palindromatic part exist, the situation is symmetric
// we don't have to check the opposite direction
return fromStart;
}
// try from the end
int fromEnd[] = new int[2];
findMiddlePart( fromEnd, s, lo, hi, halfCounts, middleChar, true );
// take the shorter
if( fromEnd[1]-fromEnd[0] < fromStart[1]-fromStart[0] ) {
return fromEnd;
} else {
return fromStart;
}
}
static boolean findMiddlePart( int[] result, String s, int lo, int hi, Map<Character,Integer> halfCounts, char middleChar, boolean backwards ) {
Map<Character,Integer> limits = new HashMap<>(halfCounts);
int pos, direction, end, oth;
if( backwards ) {
pos = hi;
direction = -1;
end = (lo+hi)/2; // mid rounded down
oth = (lo+hi+1)/2; // mid rounded up
} else {
pos = lo;
direction = 1;
end = (lo+hi+1)/2; // mid rounded up
oth = (lo+hi)/2; // mid rounded down
}
// scan until we run out of the limits
while(true) {
char c = s.charAt(pos);
int limit = limits.get(c);
if( limit <= 0 ) {
break;
}
limits.put(c,limit-1);
pos += direction;
}
// whether we reached the middle
boolean middleExists = pos == end && ( oth != end || s.charAt(end) == middleChar );
if( middleExists ) {
// scan through the middle until we find the first non-palindromic character
while( s.charAt(pos) == s.charAt(oth) ) {
pos += direction;
oth -= direction;
}
}
// prepare the resulting interval
if( backwards ) {
result[0] = lo;
result[1] = pos+1;
} else {
result[0] = pos;
result[1] = hi+1;
}
return middleExists;
}
static Map<Character,Integer> countChars( String s, int lo, int hi ) {
Map<Character,Integer> charCounts = new HashMap<>();
for( int i = lo ; i <= hi ; i++ ) {
char c = s.charAt(i);
int cnt = charCounts.getOrDefault(c,0);
charCounts.put(c,cnt+1);
}
return charCounts;
}
static boolean palindromePossible(Map<Character,Integer> charCounts) {
int oddCnt = 0;
for( int cnt : charCounts.values() ) {
if( (cnt % 2) != 0 ) {
oddCnt++;
if( oddCnt > 1 ) {
return false; // can not be made palindromic
}
}
}
return true;
}
static char findMiddleChar( Map<Character,Integer> charCounts ) {
Map<Character,Integer> halfCounts = new HashMap<>();
for( Map.Entry<Character,Integer> e : charCounts.entrySet() ) {
char c = e.getKey();
int cnt = e.getValue();
if( (cnt % 2) != 0 ) {
return c;
}
}
return 0;
}
static Map<Character,Integer> halfValues( Map<Character,Integer> charCounts ) {
Map<Character,Integer> halfCounts = new HashMap<>();
for( Map.Entry<Character,Integer> e : charCounts.entrySet() ) {
char c = e.getKey();
int cnt = e.getValue();
halfCounts.put(c,cnt/2); // we round *down*
}
return halfCounts;
}
static String repeat(char c, int cnt ) {
return cnt <= 0 ? "" : String.format("%"+cnt+"s","").replace(" ",""+c);
}
static void testReshuffle(String s ) {
int rng[] = findReshuffleRange( s );
if( rng == null ) {
System.out.println("Result : '"+s+"' is not palindromizable");
} else if( rng[0] == rng[1] ) {
System.out.println("Result : whole '"+s+"' is a palindrome");
} else {
System.out.println("Result : '"+s+"'");
System.out.println(" "+repeat('-',rng[0])+repeat('X',rng[1]-rng[0])+repeat('-',s.length()-rng[1]) );
}
}
public static void main (String[] args) {
testReshuffle( "abcdefedcba" );
testReshuffle( "abcdcdeeba" );
testReshuffle( "abcfdeedcba" );
testReshuffle( "abcdeedbca" );
testReshuffle( "abcdefcdeba" );
testReshuffle( "abcdefgfcdeba" );
testReshuffle( "accdefcdeba" );
}
}
你可以這樣使用
bool morethanone(string s, char c)
{
// Count variable
bool res = false;
for (int i=0;i < s.length(); i++)
// checking character in string
if (s[i] == c)
res++;
if(res > 1)
return true;
else
return false;
}
int getsubstringlength(string text)
{
int result = 0;
for (int i = 0; i < text.length(); i++)
{
if(morethanone(text, text[i]))
result++;
}
return result;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.