简体   繁体   中英

Where is the flaw in my algorithm to find the size of smallest substring containing an exact character set?

The setup is that I have a string like

s = "GAAATAAA" 

and a dictionary like

surpdic = { 'A' -> 4 }

The meaning of the dictionary is that s has 4 surplus A characters.

What my algorithm seeks to find is the size of the smallest substring of s that contains 4 A s. I can't figure out why it is not working all of the test cases.

It's supposed to work like

GAAATAAA
 ||| |||
 i|| j||  j - i = 4, mindiff = 4
  ||  ||
  i|  j|  j - i = 4, mindiff = 4
   |   | 
   i   j  j - i = 4, mindiff = 4

on the example I provided. In other words, from left to right in the string, find the first span that contains all the characters, then effectively take out the left pointer and move it to the the beginning of the next possible span; all the while keep track of the minimum span.

int mindiff = Int32.MaxValue; 
int left = 0; 
while(!surpdic.ContainsKey(s[left++]));
for(int right = left; right < s.Length; ++right) 
{                   
    if(surpdic.ContainsKey(s[right])) 
        surpdic[s[right]] -= 1; 
    if(surpdic.Values.All(count => count == 0)) 
    {
        int diff = right - left; 
        if(diff < mindiff) 
            mindiff = diff;

        surpdic[s[left]] += 1; 
        while(!surpdic.ContainsKey(s[left++])); 
    }
}

Edit: So here's a case that is giving me a runtime error.

using System.IO;
using System.Linq;
using System.Text;
using System;
using System.Collections.Generic;
public class Solution
{   

    static int SmallestSubstringContainingChars(string source, Dictionary<char,int> surpdic)
    {
        int mindiff = Int32.MaxValue; 
        int left = 0; 
        while(!surpdic.ContainsKey(source[left++]));
        for(int right = left; right < source.Length; ++right) 
        {                   
            if(surpdic.ContainsKey(source[right])) 
                surpdic[source[right]] -= 1; 
            if(surpdic.Values.All(count => count == 0)) 
            {
                int diff = right - left; 
                if(diff < mindiff) 
                    mindiff = diff;

                surpdic[source[left]] += 1; 
                while(!surpdic.ContainsKey(source[left++])); 
            }
        }
        return mindiff + 1;
    }

    public void Main(string[] args)
    {
        string s = "ACTGATTT";
        Dictionary<char,int> d = new Dictionary<char,int>() { { 'A' , 1 }, { 'T' , 3 } };
        Console.WriteLine( SmallestSubstringContainingChars(s,d));
    }
}

I found many problems in your code.

First the way you were incrementing left.

Also, you are modifying the dictionary, so the next executions would start with a wrong dictionary, this is why I am creating a copy.

Don't decrement the dictionary entry if its value is already 0, otherwise your All code will not work.

Check the code below and if you don't understand anything, comment below. It will return -1 if the desired pattern is not found:

static int SmallestSubstringContainingChars(string source, Dictionary<char, int> surpdic)
{
    int mindiff = -2;

    int left = 0;
    while (left<source.Length)
    {
        if (surpdic.ContainsKey(source[left]))
        {
            Dictionary<char, int> md = new Dictionary<char, int>(surpdic);
            md[source[left]] -= 1;
            for (int right = left; right < source.Length; ++right)
            {
                if (md.ContainsKey(source[right]) && md[source[right]]>0)
                    md[source[right]] -= 1;
                if (md.Values.All(count => count == 0))
                {
                    int diff = right - left;
                    if (mindiff==-2 || diff < mindiff)
                        mindiff = diff;
                }
            }
        }
        left++;
    }
    return mindiff + 1;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM