Saturday, 31 January 2015

Deleting a node in a linked list when only a reference to only that very node is given

public static boolean delNode(LinkedlIstNode n )
{
    if ( n  ==  null || n.next == null )
    {
         //invalid linked list node
        return false ;
    }
    else
    {
        n = n.next.data ;
        n = n.next ;
        return true ;
    }   
}


A situation arises if given node n is last node . We can set last  node as a sentinal  of a dummy node.

Find kth to the last ellement in a linked list

kth to the last element would be at [length-k] element , if the length of a linked list.
But since length is not known, we can either use iteration or recursion.

For recursion -
To simply print the kth to the least element in singly linked list , use a counter variable which increments itself
when each time the return statement is executed during recursion.
When counter equals "k" , print the value of node at that instance .
Recursion mostly imploys counter manipulation -

public static int nthToTheLast( LinkedListNode head , int k  )
{
    //base case
    if ( head == null )
        return 0 ;
   
    //recur to reach end of the list
    int counter = nthToTheLast(  head.next , int k  ) + 1 ;
    if( counter == k )
        System.out.println(head.data);
    return counter ;
   

}

However if the question demands to return a kth to the last "node" , since we can only return a single Object at one time, an object of
a suitable wrapper class having integer value of the counter saved can be passed on each instance of recursion as in JAVA  we dont have
pointers to pass by reference , but a wrapper class can help to mimic it -
For JAVA -

public class IntWrapper()
{
    public int val = 0 ;
}

public LinkListNode nthToTheLast(LinkListNode head , int  k , IntWrapper counter)
{
    //base case
    if( head == null) return 0 ;
   
    LinkListNode =  nthToTheLast(LinkListNode head , int  k , IntWrapper counter) ;
    if ( ++counter.val == k )
        return head ; // we have found ours kth element

    return node ;

}



Also, using C++ feature of pass by reference , an allias of the counter can be manipulated without using wrapper class -

node* nthToTheLast( Node* head , int  k , int& counter)
{
    if( head == NULL) return NULL ; //base case
   
    node&* result = nthToTheLast( Node* head , int  k , int& counter);
    if(++counter == k )
        return head;
    return result;
}


All recursive algos for this case are O(n) for both space and time but clean .
For O(1) space complexity , the runnining technique , using 2 pointers for linked list can be used as follows -

 public static LinkListNode nthToTheLastNode( LinkListNode head ,  int  k  )
 {
    LinkListNode p1 = p2 = head ;
   
    //iterate p2 n position from start , such that difference between positions of p2 and p1 is k
    for( int  i = 0 ; i < k - 1 ; ++i)
    {
        if( p2 == null ) return null ; // list is too small
            p2 = p2.next ;
    }
   
    if (p2 == null ) return  null ; // Error check : list is small
       
    //now move p1 and p2 with same pace ,  till p2 reaches end of the list.
    // at this instance , p1 will be at kth to the last node
    while ( p2.next != null )
    {
            p2 = p2.next ;
            p1 = p1.next ;
    }
   
    return p1 ;
   
   
 }

Remove Duplicates from a linked lisr

With a HashSet as buffer = Time = O(n), space = O(n)
Using two pointer technique - running method -  Time = O(n^2) Space = O(1)

// with HashSet as buffer
public static removeDuplicates(LinkedListNode head)
{
    HashSet<Integer>set =  new HashSet<Integer>();
    LinkedList ptr = head, prev = null;
    while(ptr != null )
    {
   
        if(set.contains(ptr.data))
        {
            prev.next = ptr.next;
        }
        else
        {
            set.add(ptr.data);
            prev = ptr;
        }
        ptr = ptr.next;
    }
}


//using 2-point pointer running technique

public static removeDuplicates(LinkedListNode head)
{
    LinkedList p1 = head;
    LinkedList p2 = p1.next ;
    LinkedList prev = null
    while( p1.next != null )
    {
        while( p2 != null )
        {
            if( p2.data == p1.data )
            {
                prev.next  = p2.data;
            }
            else
            {
                prev = p2;
            }
            p2  = p2.next;
           
        }
    }
}

Check if a string is a rotation of other given String




In a rotation we cut a string at a rotation point such that on rotation eg -
jimmy <=> myjim
So ,
s1 = "jimmy" = x + y where y = "my" and x = "jim" 
s2 = "myjim" = y + x
So if a rotated string  "myjim" has to be a rotation of "jimmy" then it should be a substring of  - xyxy = "jimmyjimmy" = s1s1

So checking if a string "myjim" is a substring of a String xyxy = "jimmyjimmy" will prove that it is an rotation of String xy = "jimmy"
 



public  isRot(String s1 , String s2)
{
    int len =  s1.length();
    // if both  strings are of same length and not empty
    if(len == s2.length() && len >= 0  )
    {
        // concatanate string s1 within new buffer
        String s1s1 = s1+s1;
        return isSubString(s1s1 , s2);
    }
    return false;
   
}


public static boolean isSubString(String big , String small)
{
    if(big.indexOf(small) >= 0)
        return ture ;
    else
        return false;
}

Check if two strings are permuatations of eachother

public static boolean permutation (String s, String t)
{
    //  check if they are of same lenght
    if( s.lenght() != t.length() )
    {
        return false;
    }
   
    int letters [] = new int[128] ; // for ASCII strings
   
    char[] s_array = s.toCharArray();
   
    for( char c : s_array)// count number of each character in s
    letters[c]++;
   
    for( int i = 0 ; i < t.length() ; ++i)
    {
        int c = (int) t.charAt(i);
        if(--letters[c] < 0 )
        return false
    }
    return true;
}

Friday, 30 January 2015

Reverse a String

void reverse(char* str)
{
    char* end = str;
   
    char tmp;
   
    if(str)
    {
        //find the end of the string
        while(end) ++end;
   
        --end; // since the last character is the null character
   
        //swap the elements starting from start and end till pointers meet in middle at same address
        while(str < end )
        {
            tmp = *str;
            *str++ = *end ;
            *end-- = tmp;
   
        }
    }
}

Check if a String is made up of unique characters

//only for lower case letters between a-z , bit vector method
    public static boolean isUniqueChars(String str)
   
    {
        int length =  str.length();
       
        //for ASCII string
        if(length > 128)
        {
            return false;
        }
       
        int checker = 0 ; // bit vector
       
        for(int i = 0 ; i < length ; ++i)
        {
            int val = str.charAt(i) - 'a';
            if( ( checker & ( 1 << val ) ) > 0 ) return false ; // check if the character's bit position in bit vector is already 'on'
            checker |= ( 1 << val ); // turn the bit on for character's position
        }
       
        return  true ;
       
    }
   

Arrays and String - Comman Techniques



HashTables -
    Data Structures mapping keys to the values for highly efficient lookup.
   
    2 parts - An underlying array
              A hash()
    A hash() maps keys to an integer , which indicates index in the array . The object is stored at that index.
   
    Trivial Style  -
        Create an array equal to the size of all possible key such that object allocation takes on index generated by hash(key)

    Pitfalls -
        Requires unique hash values for all keys to prevent overwrite
        To prevent "collisions" arrays need to be extremely large
   
    Optimal Solutions -
        Linked List -
                 Store objects in a linked list at index generated by  (  hash(key) % array_length  ) .
                 To get object at a particular key , we must search linked list at that index for this key
        BST -
                 Guarrantees O( log n ) lookup time , since we can keep a tree balanced .
                 Additionally we may use less space , since a large array no needs to be allocated in the very beginning.
                 Creating a BST at each bucket of ours HashMap ,instead of linked lists for degenerate hash(key) % array_length values , can bring
                 down total complexity  -
                Using LinkedList -  O(1) + O(n) - to search in the linked list
                Using BST -  O(1) + O(log n)
       
example  -
            public HashMap< Integer , Student > buildMap( Student[] students )
            {
                HashMap<Integer , Student> map =  new HashMap<Integer , Student>();
                for(Student s : students) map.append(s.getId() , s );
                return map;
            }
               

ArrayList -
            A dynamically resizing array , resizing when needed and still providing O(1) access .
            The array doubles in size , when it is full  taking O(n) time which is so rare such that amortized time is still O(1)
           
        eg. -
        public ArrayList<String> merge ( String[] words , String[] more )
        {
            ArrayList<String> sentence = new ArrayList<String>();
            for(String s : words) sentence.add(s);
            for(String s : words) sentence.add(s);
            return sentence;
        }
   
   
StringBuffer -

    A trivial style of concatanating the string is as follows , what would be its running time
    assuming all strings in array are of length x and there are n strings  -
    public String joinWords(String words[])
    {
        String sentence = "";
        for(String w : words)
        {
            sentence = sentence + words ;
        }
        return sentence;
    }
   
    On each concatanation a new copy of the string is created and two strings are copied character by character.
    First iteration -  x characters copied
    Second iteration - 2x characters copied
    .....
    ........
    ..........
    Total copying instances (assighnments) = x ( 1 + 2 + 3.. n ) = x * ( n*(n+1)/2 ) = O(x * n^2)
   
While StringBuffer can avaoid this problem as it simply creates an array of all the strings , copying them back to a string only when necessary

        public String joinWords(String words[])
    {
        StringBuffer sentence = "";
        for(String w : words)
        {
            sentence.append(w);
        }
        return sentence.toString();
    }