在C ++中找到左右相等的最长子串

时间:2011-12-12 02:47:36

标签: c++ substring

我正在解决一个问题,我遇到了一些问题:

  

完成函数getEqualSumSubstring,它接受一个参数。单个参数是一个字符串s,它只包含非零数字。   该函数应打印s的最长连续子串的长度,使得子串的长度为2 * N位,最左边的N位的总和等于最右边的N位的总和。如果没有这样的字符串,则您的函数应该打印0。

int getEqualSumSubstring(string s) {
int i=0,j=i,foundLength=0;
    for(i=0;i<s.length();i++)
    {
        for(j=i;j<s.length();j++)
        {
            int temp = j-i;
            if(temp%2==0)
            {
                int leftSum=0,rightSum=0;
                string tempString=s.substr(i,temp);
                for(int k=0;k<temp/2;k++)
                {
                    leftSum=leftSum+tempString[k]-'0';
                    rightSum=rightSum+tempString[k+(temp/2)]-'0';
                }
                if((leftSum==rightSum)&&(leftSum!=0))
                    if(s.length()>foundLength)
                    foundLength=s.length(); 
            }
        }
    }
    return(foundLength);

}

问题是这段代码适用于某些样本而不适用于其他样本。由于这是一个考试类型的问题,我也没有测试用例。

8 个答案:

答案 0 :(得分:3)

此代码有效

int getEqualSumSubstring(string s) {
    int i=0,j=i,foundLength=0;
    for(i=0;i<s.length();i++)
    {
        for(j=i;j<s.length();j++)
        {
            int temp = j-i+1;

            if(temp%2==0)
            {
                int leftSum=0,rightSum=0;
                string tempString=s.substr(i,temp);
                // printf("%d ",tempString.length());
                for(int k=0;k<temp/2;k++)
                {
                    leftSum=leftSum+tempString[k]-48;
                    rightSum=rightSum+tempString[k+(temp/2)]-48;
                }
                if((leftSum==rightSum)&&(leftSum!=0))
                    if(tempString.length()>foundLength)
                    foundLength=tempString.length(); 
            }
        }
    }
    return(foundLength);
}

临时变量必须是j-i + 1。否则,将不包括整个字符串作为答案的情况。此外,我们需要做出Scott建议的更改。

答案 1 :(得分:2)

这是我可以确认工作的解决方案。上面的那些对我来说并没有真正起作用 - 他们以某种方式给了我编译错误。我在InterviewStreet上得到了同样的问题,提出了一个不错的,不完整的解决方案,适用于9/15的测试用例,因此我不得不花费更多的时间进行编码。

这个想法是,不是关心得到左右总和(这也是我最初做的),我将从给定输入的每一半(左半部分和右半部分)中获得所有可能的子串,排序并将它们附加到两个单独的列表,然后查看是否有任何匹配。

为什么?

说字符串“423”和“234”具有相同的总和;如果我对它们进行排序,它们都将是“234”并因此匹配。由于这些数字必须是连续且相等的长度,我不再需要担心必须将它们作为数字添加并检查。

所以,例如,如果我给了12345678,那么在左侧,for循环将给我:

[1,12,123,1234,2,23,234,3,34]

在右边:

[5,56,567,5678,...]

等等。

但是,我只考虑长度至少为2的子串。

我将每个子字符串附加到ArrayLists中,这些子字符串通过转换为字符数组然后转换回字符串进行排序。

现在所有这一切都已完成,下一步是查看这两个ArrayLists中是否存在相同数字的相同字符串。我只是根据temp_a的第一个字符串检查每个temp_b的字符串,然后针对temp_a的第二个字符串检查,依此类推。

如果我得到一个匹配(比如“234”和“234”),我会将那些匹配的子串的长度设置为我的tempCount(tempCount = 3)。我还有另一个名为'count'的变量来跟踪这些匹配子串的最大长度(如果这是匹配的第一次出现,那么count = 0会被tempCount = 3覆盖,所以count = 3)。

对于变量 int end 的奇数/偶数字符串长度,原因是因为在代码行s.length()/ 2 + j中,是长度的输入恰好是11,然后:

s.length()= 11

s.length()/ 2 = 11/5 = 5.5 = 5

所以在for循环中,s.length()/ 2 + j,其中j在s.length()/ 2处最大,将变为:

5 + 5 = 10

这不足以获得字符串最后一个索引所需的s.length()。

这是因为子串函数要求的结束索引比你为charAt(i)所做的更大。

为了演示,输入“47582139875”将生成以下输出: [47,457,4578,24578,57,578,2578,58,258,28]&lt; - 来自左半部分的子串 [139,1389,13789,135789,389,3789,35789,789,5789,578]&lt; - 来自右半部分的子串 578&lt; - 最长的匹配者 6 < - 长度'578'x 2

public static int getEqualSumSubtring(String s){

    // run through all possible length combinations of the number string on left and right half
    // append sorted versions of these into new ArrayList

    ArrayList<String> temp_a = new ArrayList<String>();
    ArrayList<String> temp_b = new ArrayList<String>();

    int end; // s.length()/2 is an integer that rounds down if length is odd, account for this later 

    for( int i=0; i<=s.length()/2; i++ ){
        for( int j=i; j<=s.length()/2; j++ ){
            // only account for substrings with a length of 2 or greater
            if( j-i > 1 ){ 
                char[] tempArr1 = s.substring(i,j).toCharArray();
                Arrays.sort(tempArr1);
                String sorted1 = new String(tempArr1);
                temp_a.add(sorted1);
                //System.out.println(sorted1);

                if( s.length() % 2 == 0 )
                    end = s.length()/2+j;
                else // odd length so we need the extra +1 at the end
                    end = s.length()/2+j+1; 
                char[] tempArr2 = s.substring(i+s.length()/2, end).toCharArray();
                Arrays.sort(tempArr2);
                String sorted2 = new String(tempArr2);
                temp_b.add(sorted2);
                //System.out.println(sorted2);
            }

        }

    }

    // For reference
    System.out.println(temp_a);
    System.out.println(temp_b);

    // If the substrings match, it means they have the same sum

    // Keep track of longest substring
    int tempCount = 0 ;
    int count = 0;
    String longestSubstring = "";

    for( int i=0; i<temp_a.size(); i++){
        for( int j=0; j<temp_b.size(); j++ ){
            if( temp_a.get(i).equals(temp_b.get(j)) ){

                tempCount = temp_a.get(i).length();

                if( tempCount > count ){
                    count = tempCount;
                    longestSubstring = temp_a.get(i);

                }
            }

        }
    }

    System.out.println(longestSubstring);
    return count*2;
}

答案 2 :(得分:2)

这是我对这个问题的解决方案,包括测试。我添加了一个额外的功能只是因为我觉得它使解决方案比上面的解决方案更容易阅读。

#include <string>
#include <iostream>

using namespace std;

int getMaxLenSumSubstring( string s ) 
{
    int N = 0; // The optimal so far...

int leftSum = 0, rightSum=0, strLen=s.size();
int left, right;

for(int i=0;i<strLen/2+1;i++) {
    left=(s[i]-int('0')); right=(s[strLen-i-1]-int('0'));
    leftSum+=left; rightSum+=right;

    if(leftSum==rightSum) N=i+1;
}

return N*2;
}

int getEqualSumSubstring( string s ) {
    int maxLen = 0, substrLen, j=1;

for( int i=0;i<s.length();i++ ) {
    for( int j=1; j<s.length()-i; j++ ) {
        //cout<<"Substring = "<<s.substr(i,j);
        substrLen = getMaxLenSumSubstring(s.substr(i,j));
        //cout<<", Len ="<<substrLen;
        if(substrLen>maxLen) maxLen=substrLen;
    }
}

return maxLen;
}

以下是我跑过的一些测试。基于上面的例子,他们似乎是正确的。

int main() {
    cout<<endl<<"Test 1 :"<<getEqualSumSubstring(string("123231"))<<endl;

    cout<<endl<<"Test 2 :"<<getEqualSumSubstring(string("986561517416921217551395112859219257312"))<<endl;

    cout<<endl<<"Test 3:"<<getEqualSumSubstring(string("47582139875"))<<endl;

}

答案 3 :(得分:1)

以下代码不应使用tempString.length()而不是s.length()

if((leftSum==rightSum)&&(leftSum!=0))
    if(s.length()>foundLength)
        foundLength=s.length(); 

答案 4 :(得分:1)

 Below is my code for the question... Thanks !!


    public class IntCompl {

        public String getEqualSumSubstring_com(String s)
        {
            int j;
            int num=0;
            int sum = 0;
            int m=s.length();

            //calculate String array Length

            for (int i=m;i>1;i--)
            {
                sum = sum + m;
                m=m-1;
            }
            String [] d = new String[sum];
            int k=0;
            String ans = "NULL";

            //Extract strings

            for (int i=0;i<s.length()-1;i++)
            {
            for (j=s.length();j>=i+1;k++,j--)
            {
                num = k;
                d[k] = s.substring(i,j);
            }
            k=num+1;
            }

            //Sort strings in such a way that the longest strings precede...

            for (int i=0; i<d.length-1; i++)
            {
                for (int h=1;h<d.length;h++)
                {
                if (d[i].length() > d[h].length())
                 {
                    String temp;
                    temp=d[i];
                    d[i]=d[h];          
                    d[h]=temp;
                 }
                }       
            }

            // Look for the Strings with array size 2*N (length in even number) and such that the 
            //the sum of left N numbers is = to the sum of right N numbers.
            //As the strings are already in decending order, longest string is searched first and break the for loop once the string is found.

            for (int x=0;x<d.length;x++)
            {
                int sum1=0,sum2=0;
                if (d[x].length()%2==0 && d[x].length()<49)
                {
                    int n;
                    n = d[x].length()/2;
                    for (int y=0;y<n;y++)
                    {
                        sum1 = sum1 + d[x].charAt(y)-'0';
                    }
                    for (int y=n;y<d[x].length();y++)
                    {
                        sum2 = sum2 + d[x].charAt(y)-'0';
                    }
                    if (sum1==sum2)
                    {
                        ans = d[x];
                        break;
                    }

                }
            }
                return ans;

            }
        }

答案 5 :(得分:1)

以下是此问题的完整Java程序。 复杂度是O(n ^ 3) 然而,这可以用O(n ^ 2)来解决。对于O(n ^ 2)复杂度解,请参考this link

import java.util.Scanner;
import static java.lang.System.out;
 public class SubStringProblem{
  public static void main(String args[]){
 Scanner sc = new Scanner(System.in);
 out.println("Enter the Digit String:");
 String s = sc.nextLine();
 int n = (new SubStringProblem()).getEqualSumSubString(s);
 out.println("The longest Sum SubString is "+n);
 }
    public int getEqualSumSubString(String s){
 int N;
 if(s.length()%2==0)
 {
    //String is even
    N = s.length();     
 }
 else{ 
    //String is odd
    N=s.length()-1;
 }
 boolean flag =false;
 int sum1,sum2;
 do{    
    for(int k=0;k<=s.length()-N;k++){   
        sum1=0;
        sum2=0;
        for(int i =k,j=k+N-1;i<j;i++,j--)
        {   
            sum1=sum1 + Integer.parseInt(s.substring(i,i+1));
            sum2+=Integer.parseInt(s.substring(j,j+1));
        }
        if(sum1==sum2){
        return N;
        }
    }   
    N-=2;
 flag =true;
}while(N>1);
return -1;
}
}

答案 6 :(得分:0)

这两行中48号的理由是什么?

for(int k=0;k<temp/2;k++)
{
    leftSum=leftSum+tempString[k]-48;
    rightSum=rightSum+tempString[k+(temp/2)]-48;
}

我只是过于好奇,并且想听听它背后的原因,因为我有一个类似的解决方案,但没有48,它仍然有效。但是,我添加了48仍然得到了正确答案。

答案 7 :(得分:0)

简单的解决方案。 O(N * N)。 s - 输入字符串。

var longest = 0;
for (var i = 0; i < s.length-1; i++) {
    var leftSum = rightSum = 0;

    for (var j = i, k = i+1, l = 2; j >=0 && k < s.length; j--, k++, l+=2) {
        leftSum += parseInt(s[j]);
        rightSum += parseInt(s[k]);

        if (leftSum == rightSum && l > longest) {
            longest = l;
        }
    }
}

console.log(longest);