如何查找包含两个唯一重复字符的最长子字符串

时间:2013-02-21 08:02:29

标签: java string-matching

任务是找到给定字符串中由任意两个唯一重复字符组成的最长子字符串 防爆。在输入字符串“aabadefghaabbaagad”中,最长的字符串是“aabbaa”

我想出了以下解决方案,但想知道是否有更有效的方法来做同样的事情

import java.util.*; 

public class SubString {
    public static void main(String[] args) { 
    //String inStr="defghgadaaaaabaababbbbbbd";
    String inStr="aabadefghaabbaagad";
    //String inStr="aaaaaaaaaaaaaaaaaaaa";
    System.out.println("Input string is         "+inStr);

    StringBuilder sb = new StringBuilder(inStr.length());
    String subStr="";
    String interStr="";
    String maxStr="";
    int start=0,length=0, maxStart=0, maxlength=0, temp=0;

    while(start+2<inStr.length())   
    {    int i=0;
         temp=start;
         char x = inStr.charAt(start);
         char y = inStr.charAt(start+1);
         sb.append(x);
         sb.append(y);

         while( (x==y) && (start+2<inStr.length()) )
         {    start++;
              y = inStr.charAt(start+1);
              sb.append(y);
         }

         subStr=inStr.substring(start+2);
         while(i<subStr.length())
         {    if(subStr.charAt(i)==x || subStr.charAt(i)==y )
              {    sb.append(subStr.charAt(i));
                   i++;
              }
              else
                   break;
         }

         interStr= sb.toString();
         System.out.println("Intermediate string "+ interStr);
         length=interStr.length();
         if(maxlength<length)
         {    maxlength=length;
              length=0;
              maxStr = new String(interStr);
              maxStart=temp;
         }

         start++;
         sb.setLength(0);
   }

   System.out.println("");
   System.out.println("Longest string is "+maxStr.length()+" chars long "+maxStr);  
}
}

7 个答案:

答案 0 :(得分:9)

这里有一个暗示可能会引导你走向线性时间算法(我假设这是作业,所以我不会给出整个解决方案):在你找到一个既不等于{的字符的位置{1}}也不是x,没有必要一直回到y并重新开始搜索。我们取字符串start + 1。在您看到aabaaddaa且下一个字符为aabaa的位置,在索引1或2处重新启动搜索没有意义,因为在这些情况下,您只会获得{{1在再次点击d之前或abaa。事实上,您可以将baa直接移动到索引3(最后一组d s的第一个索引),因为您已经知道{{1}存在连续的序列最多start,您可以将a移至索引5并继续。

编辑:下面的伪代码。

a

答案 1 :(得分:1)

同样的问题,我写了这段代码

public int getLargest(char [] s){
    if(s.length<1) return s.length;
    char c1 = s[0],c2=' ';
    int start = 1,l=1, max=1;

    int i = 1;
    while(s[start]==c1){
        l++;
        start++;
        if(start==s.length) return start;
    }

    c2 = s[start];
    l++;

    for(i = l; i<s.length;i++){
        if(s[i]==c1 || s[i]==c2){
            if(s[i]!=s[i-1])
                start = i;
            l++;
        }
        else {
            l = i-start+1;  
            c1 = s[start];
            c2 = s[i];
            start = i;
        }
        max = Math.max(l, max);
    }
    return max;
}

答案 2 :(得分:0)

所以我想到的方法是分两步解决它

  • 扫描整个字符串以查找相同字母的连续流
  • 循环提取的片段并将它们浓缩,直到你得到一个间隙。

这样你也可以修改逻辑来扫描任何长度的最长子串而不仅仅是2。

class Program
{

    static void Main(string[] args)     
    {
        //.         
        string input = "aabbccdddxxxxxxxxxxxxxxxxx";
        int max_chars = 2;

        //.
        int flip = 0;

        var scanned = new List<string>();

        while (flip > -1)
        {
            scanned.Add(Scan(input, flip, ref flip));
        }

        string found = string.Empty;
        for(int i=0;i<scanned.Count;i++)
        {
            var s = Condense(scanned, i, max_chars);
            if (s.Length > found.Length)
            { 
                found = s;
            }
        }

        System.Console.WriteLine("Found:" + found);
        System.Console.ReadLine();


    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="s"></param>
    /// <param name="start"></param>
    /// <returns></returns>
    private static string Scan(string s, int start, ref int flip)
    { 
        StringBuilder sb = new StringBuilder();

        flip = -1;

        sb.Append(s[start]);

        for (int i = start+1; i < s.Length; i++)
        {
            if (s[i] == s[i - 1]) { sb.Append(s[i]); continue; } else { flip=i; break;}
        }

        return sb.ToString();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="list"></param>
    /// <param name="start"></param>
    /// <param name="repeat"></param>
    /// <param name="flip"></param>
    /// <returns></returns>
    private static string Condense(List<string> list, int start, int repeat)
    {
        StringBuilder sb = new StringBuilder();

        List<char> domain = new List<char>(){list[start][0]};

        for (int i = start; i < list.Count; i++)
        {
            bool gap = false;

            for (int j = 0; j < domain.Count; j++)
            {
                if (list[i][0] == domain[j])
                { 
                    sb.Append(list[i]);
                    break;
                }
                else if (domain.Count < repeat)
                {
                    domain.Add(list[i][0]);
                    sb.Append(list[i]);
                    break;
                }
                else
                {
                    gap=true;
                    break;
                }
            }

            if (gap) { break;}
        }

        return sb.ToString();
    }


}

答案 3 :(得分:0)

一般解决方案:包含K个唯一字符的最长子字符串。

int longestKCharSubstring(string s, int k) {
    int i, max_len = 0, start = 0;
    // either unique char & its last pos
    unordered_map<char, int> ht;

    for (i = 0; i < s.size(); i++) {
        if (ht.size() < k || ht.find(s[i]) != ht.end()) {
            ht[s[i]] = i;
        } else {
            // (k + 1)-th char
            max_len = max(max_len, i - start);
            // start points to the next of the earliest char
            char earliest_char;
            int earliest_char_pos = INT_MAX;
            for (auto key : ht)
                if (key.second < earliest_char_pos)
                    earliest_char = key.first;
            start = ht[earliest_char] + 1;
            // replace earliest_char
            ht.erase(earliest_char);
            ht[s[i]] = i;
        }
    }
    // special case: e.g., "aaaa" or "aaabb" when k = 2
    if (k == ht.size())
        max_len = max(max_len, i - start);

    return max_len;
}

答案 4 :(得分:0)

let paths = fs::read_dir(&Path::new(
  &env::current_dir().unwrap())).unwrap();

let names =
paths.filter_map(|entry| {
  entry.ok().and_then(|e|
    e.path().file_name()
    .and_then(|n| n.to_str().map(|s| String::from(s)))
  )
}).collect::<Vec<String>>();

答案 5 :(得分:0)

问题可以在O(n)中解决。想法是维护一个窗口并向窗口添加元素,直到它包含少于或等于2,如果需要,更新我们的结果。如果唯一元素超出窗口中的要求,请从左侧开始删除元素。

#code
from collections import defaultdict

def solution(s, k):
  length = len(set(list(s)))
  count_dict = defaultdict(int)
  if  length < k:
    return "-1"

  res = []
  final = []
  maxi = -1

  for i in range(0, len(s)):

    res.append(s[i])
    if len(set(res)) <= k:
      if len(res) >= maxi and len(set(res)) <= k :
        maxi = len(res)
        final = res[:]
        count_dict[maxi] += 1

    else:
      while len(set(res)) != k:
        res = res[1:]
      if maxi <= len(res) and len(set(res)) <= k:
        maxi =  len(res)
        final = res[:]
        count_dict[maxi] += 1
    return len(final)

print(solution(s, k))

答案 6 :(得分:0)

这里的想法是将每个字符的出现添加到哈希图中,并且当hasmap的大小增加超过k时,请删除不需要的字符。

DataTemplate