Online Judge Solutions

Wednesday, May 29, 2013

Longest substring which begins and ends with two unique characters

This is follow up my last post at Longest substring which contains just two unique characters

What if you are asked to find the longest substring which begins and ends with unique characters. For example, the following strings begin and end with unique characters:
  "abc" where 'a' and 'c' are unique
  "ebbcf" where 'e' and 'f' are unique

Here is my solution in (C#):
 

// ----------------------------------------------------------------------------
// Copyright (c) SimpleCoder 2013
// ----------------------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace LongestSubstring
{
 static class Program
 {
    // Find longest substring which begins and ends with unique characters. 
    // i.e. "abc" where 'a' and 'c' are unique
    // "ebbcf" where 'e' and 'f' are unique
    static string LongestSubstring(string str)
    {
        int Len = str.Length;
        // start index of current substring
        int i = 0;
        // end index of current substring
        int j = 0;
        // start index of the longest substring 
        int maxStart = 0;
        // length of the longest substring 
        int maxLen = 0;
        // Occurrence of each char in current substring
        Dictionary<char, int> CountMap = new Dictionary<char, int>();

        while (j < Len)
        {
            char ch = str[j];            
            // add current char into CountMap
            if (!CountMap.ContainsKey(ch))
                CountMap.Add(ch, 1);            else
                ++CountMap[ch];
            // Increment i until the occurrence of str[i] is 1 or i reaches j
            char ch2 = str[i];
            while (i < j && CountMap[ch2] > 1)
            {
                --CountMap[ch2];
                ch2 = str[++i];
            }
            // Update maxStart and maxLen if current substring is the longest one
            // which starts and ends with unique characters.
            if (i < j && CountMap[ch] == 1 && CountMap[str[i]] == 1 &&
                j - i >= maxLen)
            {
                maxStart = i;
                maxLen = j - i + 1;
            }
            ++j;
         }
          return str.Substring(maxStart, maxLen);
     }
     static void Main()
     {          Assert.AreEqual("", LongestSubstring(""));
          Assert.AreEqual("", LongestSubstring("a"));
          Assert.AreEqual("ab", LongestSubstring("ab"));
          Assert.AreEqual("abc", LongestSubstring("abc"));
          Assert.AreEqual("abbc", LongestSubstring("abbc"));
          Assert.AreEqual("bac", LongestSubstring("abac"));
          Assert.AreEqual("bcccccaaaccccd", LongestSubstring("abaaabcccccaaaccccdd"));
     }
   }
} 

Longest substring which contains just two unique characters

This was discussed at http://www.mitbbs.com/article_t/JobHunting/32444763.html

Here is my solution in (C#):

 // ----------------------------------------------------------------------------
// Copyright (c) SimpleCoder 2013
// ----------------------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace LongestSubstring
{
static class Program
{  
    // Find longest substring which contains just two unique characters.
    static string LongestSubstring(string str)
    {
        int Len = str.Length;
        // start index of current substring
        int i = 0;
        // end index of current substring
        int j = 0;            
        // start index of the longest substring
        int maxStart = 0;
        // length of the longest substring
        int maxLen = 0;
        // Occurrence of each char in current substring
        Dictionary<char, int> CountMap = new Dictionary<char, int>();
           
        while (j < Len) 
        {
           char ch = str[j];
           if (!CountMap.ContainsKey(ch))
               CountMap.Add(ch, 1);
           else 
               ++CountMap[ch];
           // Increment i until there are at most
           // 2 unique chars in current substring begin at i and end at j
           while (CountMap.Count > 2 && i < j)
           {
               ch = str[i];
               if (CountMap[ch] > 1) 
                   --CountMap[ch];
               else
                   CountMap.Remove(ch);                                  
               ++i;                           
           }            
           // If we got 2 chars in current substring and its length
           // is the longest so far, update maxStart and maxLen
           if (CountMap.Count == 2 && j - i >= maxLen) 
           { 
               maxStart = i; 
               maxLen = j - i + 1; 
           }                           
           ++j; 
       }
       return str.Substring(maxStart, maxLen); 
    }
    static void Main() 
    {
       Assert.AreEqual("", LongestSubstring(""));
       Assert.AreEqual("", LongestSubstring("a"));
       Assert.AreEqual("ab", LongestSubstring("ab"));
       Assert.AreEqual("cccccaaacccc", LongestSubstring("abaaabcccccaaaccccdd")); 
    } 
 }
}
 

Follow up, take a look at solution for a related but slightly different question:
Longest substring which begins and ends with two unique characters

Friday, May 10, 2013

Score of the Racers

This problem was discussed at http://www.mitbbs.com/article_t/JobHunting/32401359.html.

The Problem: A bunch of racers, each one has start time and end time.  Calculate each racer's score based on the following rule:
  
    score = The number of racers who started after and finished earlier than current racer.

Note: There is no duplicated start time or end time.

 
Let's start defining the Racer as following (in C#):
class Racer
{
     public Racer(int id, int start, int end)
   { 
      Id = id;
      Start = start;
      End = end;
      StartRank = 0;
      Score = 0;
   }
   // Id of the Racer
   public int Id { get; set; }
   // Start time
   public int Start { get; set; }
   // Finish time
   public int End { get; set; }
   // The number of racers started after and finished before current racer.
   public int Score { get; set; }
   // The number of racers started before current racer
   public int StartRank { get; set; }
}

The Algorithm:

1. Sort the Racers based on Start time.
After this sort, the StartRank is assigned to the Racers.
2.Sort the Racers based on End time in ascending order.
In other word, racers finished earlier will be processed earlier in step 3. 
3.The heart of this algorithm. Initialize an empty List called RanksList. 
For each Racer ordered by the End time in 2,
  a. The score of current racer is the number of racers who start later(StartRank is higher than current Racer's StartRank) and finished earlier(StartRank already in RanksList).
  b. Insert current Racer's StartRank into the RanksList so that all the values in RanksList are ordered ascendingly.

step 3. can be done efficiently by leveraging following feature of List<T>.BinarySearch Method 

"If the List<T> does not contain the specified value, the method returns a negative integer. You can apply the bitwise complement operation (~) to this negative integer to get the index of the first element that is larger than the search value. When inserting the value into the List<T>, this index should be used as the insertion point to maintain the sort order.
This method is an O(log n) operation, where n is the number of elements in the range."
http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx
Implementation 
static void RankRacers(Racer[] racers)
{
  Array.Sort<Racer>(racers, (a, b) => a.Start - b.Start);
  for (int i = 0; i < racers.Length; ++i)
  {
     racers[i].StartRank = i;
  }   
  Aray.Sort<Racer>(racers, (a, b) => a.End - b.End);   
  List<int> StartRanks = new List<int>();
  for (int i = 0; i < racers.Length; ++i)
  { 
    racers[i].Score = BinarySearchInsert(StartRanks, racers[i].StartRank);
  }
}          
static int BinarySearchInsert(List<int> processedRanks, int startRank)
{
   int index = processedRanks.BinarySearch(startRank);
   index = (index < 0) ? ~index : index;
   int score = processedRanks.Count - index;
   processedRanks.Insert(index, startRank);  
  
   return score;        
} 

Test code:
static void PrintRacerScores(Racer[] racers)
{
   foreach (Racer racer in racers)
   {     
      Console.WriteLine("Racer - " + racer.Id);
      Console.WriteLine("Start - " + racer.Start);
      Console.WriteLine("End - " + racer.End);      Console.WriteLine("Score - " + racer.Score); 
      Console.WriteLine();
    }
} 

static void Main(string[] args)
{
   Racer[] racers = new Racer[] {
       new Racer(0, 1, 100),
       new Racer(1, 2, 10),
       new Racer(2, 3, 4),
       new Racer(3, 5, 6),
   }; 
   RankRacers(racers);   Array.Sort<Racer>(racers, (a, b) => a.Id - b.Id);
   PrintRacerScores(racers);
} 

Sample Output: 
Racer - 0
Start - 1
End - 100
Score - 3

Racer - 1
Start - 2
End - 10
Score - 2

Racer - 2
Start - 3
End - 4
Score - 0

Racer - 3
Start - 5
End - 6
Score - 0