Left God algorithm - Basic 04

Left God algorithm - Basic 04

A brief introduction to hash table

1) Hash table can be understood as a collection structure at the use level

2) If there is only key and no accompanying data value, you can use the HashSet structure (unorderderdedset in C + +)

3) If there are both key s and accompanying data value s, you can use the HashMap structure (unordered map in C + +)

4) Whether there is accompanying data or not is the only difference between HashMap and HashSet. The actual structure of the underlying is the same thing

5) Using the operations of hash table put, remove, put and get, it can be considered that the time complexity is O(1), but the constant time is relatively large

6) If the hash table is a basic type, it is internally passed by value, and the memory occupation is the size of this thing

7) If the hash table is not the basic type, it is passed internally by reference. The memory occupation is the size of the memory address of the hash table

A brief introduction to ordered tables

1) The ordered table can be understood as a set structure at the use level

2) If there is only key and no accompanying data value, you can use the TreeSet structure (called orderedset in C + +)

3) If there are both key s and accompanying data value s, you can use the TreeMap structure (called orderedmap in C + +)

4) Whether there is accompanying data or not is the only difference between TreeSet and TreeMap. The actual structure of the underlying is the same thing

5) The difference between an ordered table and a hash table is that an ordered table organizes key s in order, while a hash table does not organize at all

5) Red black tree, AVL tree, size balance tree and jump table all belong to ordered table structure, but the specific implementation of the bottom layer is different

6) If the items put into the ordered table are basic types, they are passed internally by value, and the memory occupation is the size of this item

7) If the object placed in the ordered table is not a basic type, a comparator must be provided. It is passed internally by reference. The memory occupation is the size of the object's memory address

8) No matter what the underlying implementation is, as long as it is an ordered table, it has the following fixed basic functions and fixed time complexity

Fixed operation of ordered table

1) void put(K key, V value): add a (key, value) record to the table, or update the record of key to value.

2) V get(K key): query value according to the given key and return it.

3) void remove(K key): removes the record of the key.

4) boolean containsKey(K key): ask whether there is a record about the key.

5) K firstKey(): returns the leftmost (smallest) of the sorting results of all key values.

6) K lastKey(): returns the rightmost (largest) sorting result of all key values.

7) K floatkey (k key): if a key has been stored in the table, the key is returned; Otherwise, it returns the previous key in the sorting results of all key values. Returns the maximum value of < = key

8) K ceilingKey(K key): if a key has been stored in the table, the key is returned; Otherwise, the last key in the sorting results of all key values is returned. Returns the minimum value of > = key

All the above operation time complexity is O(logN), and N is the number of records contained in the ordered table

public static class Node {
   public int value;
   public Node next;

   public Node(int val) {
      value = val;
   }
}

public static class NodeComparator implements Comparator<Node> {

   @Override
   public int compare(Node o1, Node o2) {
      return o1.value - o2.value;
   }

}

public static void main(String[] args) {
   Node nodeA = null;
   Node nodeB = null;
   Node nodeC = null;

   // The key of hashSet1 is the basic type - > int type
   HashSet<Integer> hashSet1 = new HashSet<>();
   hashSet1.add(3);
   System.out.println(hashSet1.contains(3));
   hashSet1.remove(3);
   System.out.println(hashSet1.contains(3));
   System.out.println("========1=========");

   // The key of hashSet2 is a non basic type - > node type
   nodeA = new Node(1);
   nodeB = new Node(1);
   HashSet<Node> hashSet2 = new HashSet<>();
   hashSet2.add(nodeA);
   System.out.println(hashSet2.contains(nodeA));
   System.out.println(hashSet2.contains(nodeB));
   hashSet2.remove(nodeA);
   System.out.println(hashSet2.contains(nodeA));
   System.out.println("========2=========");

   // The key of hashMap1 is the basic type - > string type
   HashMap<String, Integer> hashMap1 = new HashMap<>();
   String str1 = "key";
   String str2 = "key";
   hashMap1.put(str1, 1);
   System.out.println(hashMap1.containsKey(str1));
   System.out.println(hashMap1.containsKey(str2));
   System.out.println(hashMap1.get(str1));
   System.out.println(hashMap1.get(str2));

   hashMap1.put(str2, 2);
   System.out.println(hashMap1.containsKey(str1));
   System.out.println(hashMap1.containsKey(str2));
   System.out.println(hashMap1.get(str1));
   System.out.println(hashMap1.get(str2));

   hashMap1.remove(str1);
   System.out.println(hashMap1.containsKey(str1));
   System.out.println(hashMap1.containsKey(str2));
   System.out.println("========3=========");

   // The key of hashMap2 is non basic type - > node type
   nodeA = new Node(1);
   nodeB = new Node(1);
   HashMap<Node, String> hashMap2 = new HashMap<>();
   hashMap2.put(nodeA, "A node");
   System.out.println(hashMap2.containsKey(nodeA));
   System.out.println(hashMap2.containsKey(nodeB));
   System.out.println(hashMap2.get(nodeA));
   System.out.println(hashMap2.get(nodeB));
   hashMap2.put(nodeB, "B node");
   System.out.println(hashMap2.containsKey(nodeA));
   System.out.println(hashMap2.containsKey(nodeB));
   System.out.println(hashMap2.get(nodeA));
   System.out.println(hashMap2.get(nodeB));
   System.out.println("========4=========");

   // The key of treeSet is non basic type - > node type
   nodeA = new Node(5);
   nodeB = new Node(3);
   nodeC = new Node(7);

   TreeSet<Node> treeSet = new TreeSet<>();
   // The following code will report an error because no comparator of Node type is provided
   try {
      treeSet.add(nodeA);
      treeSet.add(nodeB);
      treeSet.add(nodeC);
   } catch (Exception e) {
      System.out.println("Error message:" + e.getMessage());
   }

   treeSet = new TreeSet<>(new NodeComparator());
   // The following code is OK because a Node type comparator is provided
   try {
      treeSet.add(nodeA);
      treeSet.add(nodeB);
      treeSet.add(nodeC);
      System.out.println("This time, all nodes have joined");
   } catch (Exception e) {
      System.out.println(e.getMessage());
   }
   System.out.println("========5=========");

   // Display common operations of ordered table
   TreeMap<Integer, String> treeMap1 = new TreeMap<>();
   treeMap1.put(7, "I'm 7");
   treeMap1.put(5, "I'm 5");
   treeMap1.put(4, "I'm 4");
   treeMap1.put(3, "I'm 3");
   treeMap1.put(9, "I'm 9");
   treeMap1.put(2, "I'm 2");
   System.out.println(treeMap1.containsKey(5));
   System.out.println(treeMap1.get(5));
   //Sort by comparator
   System.out.println(treeMap1.firstKey() + ", My youngest");
   System.out.println(treeMap1.lastKey() + ", My biggest");
   //floorKey ceilingKey
   System.out.println(treeMap1.floorKey(8) + ", All in table<=8 Of the numbers, I'm closest to 8");
   System.out.println(treeMap1.ceilingKey(8) + ", All in table>=8 Of the numbers, I'm closest to 8");
   System.out.println(treeMap1.floorKey(7) + ", All in table<=7 Of the numbers, I'm closest to 7");
   System.out.println(treeMap1.ceilingKey(7) + ", All in table>=7 Of the numbers, I'm closest to 7");
   treeMap1.remove(5);
   System.out.println(treeMap1.get(5) + ", If you delete it, it's gone");
   System.out.println("========6=========");

}

Linked list

Node structure of single linked list

class Node<V>{ 
	V value; 
	Node next; 
}

The chain formed by connecting the nodes of the above structure in turn is called single linked list structure.

Node structure of double linked list

class Node<V>{ 
	V value; 
	Node next; 
	Node last; 
}

The chain formed by connecting the nodes of the above structure in turn is called double linked list structure.

Single linked list and double linked list structures only need to give a header node head to find all the remaining nodes.

Reverse one-way and two-way linked lists

[title] realize the functions of reversing one-way linked list and reversing two-way linked list respectively

[requirement] if the length of the linked list is N, the time complexity is O(N) and the additional space complexity is

O(1)

    //Unidirectional linked list node
   public static class Node {
      public int value;
      public Node next;

      public Node(int data) {
         this.value = data;
      }
   }

   public static Node myReverseList(Node head) {
      Node p = null;
      while(head != null) {
         Node t = head.next;
         head.next = p;
         p = head;
         head = t;
      }
      return p;
   }
	//Bidirectional linked list node
   public static class DoubleNode {
      public int value;
      public DoubleNode last;
      public DoubleNode next;

      public DoubleNode(int data) {
         this.value = data;
      }
   }

   public static DoubleNode myReverseList(DoubleNode head) {
      DoubleNode p = null;
      DoubleNode newHead = null;
      
//    while(head != null) {
//       DoubleNode tmp = head.next;
//       head.next = p;
//       head.last = tmp;
//       p = head;
//       head = tmp;
//    }
//    
//    return p;

      while(head != null) {
         DoubleNode t = head.next;
         head.next = p;
         p = head;
         head = t;
      }
      newHead = p;
      while(p != null) {
         DoubleNode t = p.last;
         p.last = head;
         head = p;
         p = t;
      }

      return newHead;
   }

Print the common part of two ordered linked lists

[title] given the header pointers head1 and head2 of two ordered linked lists, print the common parts of the two linked lists.

[requirement] if the sum of the lengths of the two linked lists is N, the time complexity is O(N), and the additional space is complex

The impurity requirement is O(1)

public static class Node {
   public int value;
   public Node next;
   public Node(int data) {
      this.value = data;
   }
}

public static void myPrintCommonPart(Node head1, Node head2) {
   //Orderly linked list, traversal, who is younger, who goes back,
   //Equal output, and then go together
   System.out.print("Common Part: ");
   for (; head1 != null && head2 != null ; ) {
      if (head1.value > head2.value) {
         head2 = head2.next;
      }else if (head1.value < head2.value){
         head1 = head1.next;
      }else {
         System.out.print(head1.value+"\t");
         head1 = head1.next;
         head2 = head2.next;
      }
   }
   System.out.println();
}

Methodology of linked list problem solving in interview

1) For the written test, don't care too much about the spatial complexity, all for the time complexity

2) For the interview, time complexity still comes first, but we must find the most space-saving method

Key skills:

1) Additional data structure records (hash table, etc.)

2) Speed pointer

Judge whether a linked list is palindrome structure

[title] given the head node of a single linked list, please judge whether the linked list is palindrome structure.

[example] 1 - > 2 - > 1, return true; 1 - > 2 - > 2 - > 1, return true; 15 - > 6 - > 15, return true; 1 - > 2 - > 3, return false.

[example] if the length of the linked list is N, the time complexity reaches O(N) and the additional space complexity reaches O(1).

public static boolean myIsPalindrome1(Node head) {
   //Save it on the stack and read it out
   Stack<Node> nodes = new Stack<Node>();
   Node p = head;
   while(p != null) {
      nodes.push(p);
      p = p.next;
   }
   while(head.value == nodes.pop().value){
      if (head.next == null)
         return true;
      head = head.next;
   }
   return false;
}
// need n extra space
public static boolean isPalindrome1(Node head) {
   Stack<Node> stack = new Stack<Node>();
   Node cur = head;
   while (cur != null) {
      stack.push(cur);
      cur = cur.next;
   }
   while (head != null) {
      if (head.value != stack.pop().value) {
         return false;
      }
      head = head.next;
   }
   return true;
}

public static boolean myIsPalindrome2(Node head) {
   if (head == null || head.next == null) {
      return true;
   }
   //Store half of the stack, and then traverse the latter half and compare it with the stack. pop
   Stack<Node> nodes = new Stack<Node>();
   Node p1 = head;
   Node p2 = head;
   while(p2.next != null && p2.next.next != null) {
      p1 = p1.next;
      p2 = p2.next.next;
   }

   while(head != p1.next){
      nodes.push(head);
      head = head.next;
   }
   if (p2.next != null)   //When p2 is not the tail node, let p1 move back, that is, when the number of summary points is even
      p1 = p1.next;
   //Otherwise, there is no need to move back
   while(p1 != null) {
      if (p1.value != nodes.pop().value)
         return false;
      p1 = p1.next;
   }
   return true;
}
// need n/2 extra space
public static boolean isPalindrome2(Node head) {
   if (head == null || head.next == null) {
      return true;
   }
   Node right = head.next;
   Node cur = head;
   while (cur.next != null && cur.next.next != null) {
      right = right.next;
      cur = cur.next.next;
   }
   Stack<Node> stack = new Stack<Node>();
   //Store the latter half in the stack structure
   while (right != null) {
      stack.push(right);
      right = right.next;
   }
   //Whether the stack is empty or not is used as the condition, and there is no need to divide the situation
   while (!stack.isEmpty()) {
      if (head.value != stack.pop().value) {
         return false;
      }
      head = head.next;
   }
   return true;
}

public static boolean myIsPalindrome3(Node head) {
   if (head == null || head.next == null) {
      return true;
   }
   Node p1 = head;
   Node p2 = head;
   while(p2.next != null && p2.next.next != null) {
      p1 = p1.next;
      p2 = p2.next.next;
   }
   //p2 to the end, p1 to the middle
   p2 = p1.next;
   Node p3 = null;
   while(p2 != null) {
      Node t = null;
      t = p2.next;
      p2.next = p3;
      p3 = p2;
      p2 = t;
   }
   p2 = p3;
   //p3 is the head node in reverse order of the latter paragraph
   boolean isPalindrome = true;
   while(p3!=null) {
      if (p3.value != head.value) {
         isPalindrome = false;
         break;
      }
      p3 = p3.next;
      head = head.next;
   }
   //To restore the linked list
   p3 = null;
   while(p2 != null) {
      Node t = null;
      t = p2.next;
      p2.next = p3;
      p3 = p2;
      p2 = t;
   }
   //p3 head of the latter segment
   p1.next = p3;
   return isPalindrome;
}

// need O(1) extra space
public static boolean isPalindrome3(Node head) {
   if (head == null || head.next == null) {
      return true;
   }
   Node n1 = head;
   Node n2 = head;
   while (n2.next != null && n2.next.next != null) { // find mid node
      n1 = n1.next; // n1 -> mid
      n2 = n2.next.next; // n2 -> end
   }
   n2 = n1.next; // n2 -> right part first node
   n1.next = null; // mid.next -> null
   Node n3 = null;
   while (n2 != null) { // right part convert
      n3 = n2.next; // n3 -> save next node
      n2.next = n1; // next of right node convert
      n1 = n2; // n1 move
      n2 = n3; // n2 move
   }
   n3 = n1; // n3 -> save last node
   n2 = head;// n2 -> left first node
   boolean res = true;
   while (n1 != null && n2 != null) { // check palindrome
      if (n1.value != n2.value) {
         res = false;
         break;
      }
      n1 = n1.next; // left to mid
      n2 = n2.next; // right to mid
   }
   n1 = n3.next;
   n3.next = null;
   while (n1 != null) { // recover list
      n2 = n1.next;
      n1.next = n3;
      n3 = n1;
      n1 = n2;
   }
   return res;
}

The one-way linked list is divided into the form of small on the left, equal in the middle and large on the right according to a certain value

[title] give the head node of a single linked list, the value type of the node is integer, and then give an integer pivot.

Implement a function to adjust the linked list. The left part of the linked list is all nodes with values less than pivot, the middle part is all nodes with values equal to pivot, and the right part is all nodes with values greater than pivot.

[advanced] the following requirements are added on the basis of realizing the function of the original problem

[requirement] after adjustment, the relative order of all nodes smaller than pivot is the same as before adjustment

[requirement] after adjustment, the relative order of all nodes equal to pivot is the same as before adjustment

[requirement] after adjustment, the relative order of all nodes larger than pivot is the same as before adjustment

[requirement] the time complexity shall reach O(N), and the additional space complexity shall reach O(1).

public static Node listPartition2(Node head, int pivot) {
   Node sH = null; // small head
   Node sT = null; // small tail
   Node eH = null; // equal head
   Node eT = null; // equal tail
   Node bH = null; // big head
   Node bT = null; // big tail
   Node next = null; // save next node
   // every node distributed to three lists
   while (head != null) {
      next = head.next;
      head.next = null;
      if (head.value < pivot) {
         if (sH == null) {
            sH = head;
            sT = head;
         } else {
            sT.next = head;
            sT = head;
         }
      } else if (head.value == pivot) {
         if (eH == null) {
            eH = head;
            eT = head;
         } else {
            eT.next = head;
            eT = head;
         }
      } else {
         if (bH == null) {
            bH = head;
            bT = head;
         } else {
            bT.next = head;
            bT = head;
         }
      }
      head = next;
   }
   // small and equal reconnect
   if (sT != null) {
      sT.next = eH;
      eT = eT == null ? sT : eT;
   }
   // all reconnect
   if (eT != null) {
      eT.next = bH;
   }
   return sH != null ? sH : eH != null ? eH : bH;
}

Copy linked list with random pointer nodes

[title] a special single linked list node class is described below

class Node { 
	int value; 
	Node next; 
	Node rand; 
	Node(int val) { 
		value = val; 
	} 
}

rand pointer is a new pointer in the single linked list node structure. rand may point to any node in the linked list or null.

Given the head Node of an acyclic single linked list composed of Node types, please implement a function to copy the linked list and return the head Node of the copied new linked list.

[requirement] time complexity O(N), additional space complexity O(1)

	//Using hashmap structure, copy the corresponding relationship of key to value, and return get (head) to ok
	public static Node myCopyListWithRand1(Node head) {
		HashMap<Node, Node> map = new HashMap<Node, Node>();
		Node p = head;
		while (p != null){
			map.put(p,new Node(p.value));
			p = p.next;
		}
		p = head;
		while (p != null) {
			map.get(p).next = map.get(p.next);
			map.get(p).rand = map.get(p.rand);
			p = p.next;
		}
		return map.get(head);
	}
	//The copied node follows the original linked list node and is linked to a linked list to correspond the rand relationship to the copied node
	//Finally, separate the linked list
	public static Node myCopyListWithRand2(Node head) {
		if (head == null)
			return null;
		Node p = head;
		Node t = null;
		while (p != null) {
			t = p.next;
			p.next = new Node(p.value);
			p.next.next = t;
			p = t;
		}
		p = head;
		t = p.next;
		while (t != null) {
			t.rand = p.rand == null ? null : p.rand.next;
			if (t.next == null)
				break;
			p = p.next.next;
			t = t.next.next;
		}
		p = head;
		Node newHead = head.next;
		while (p.next != null ) {
			t = p.next;
			p.next = t.next;
			p = t;
		}
		return newHead;
	}

A series of problems about the intersection of two single linked lists

[title] give two single linked lists that may or may not have rings, head nodes head1 and head2.

Please implement a function. If two linked lists intersect, please return the first node of the intersection. If it does not intersect, null is returned

[requirement] if the sum of the lengths of the two linked lists is N, the time complexity should reach O(N) and the additional space complexity should reach O(1).

//It can be divided into two cases: all have rings and all have no rings
public static Node myGetIntersectNode(Node head1, Node head2) {
   if (head1 == null || head2 == null)
      return null;
   Node loop1 = myGetLoopNode(head1);
   Node loop2 = myGetLoopNode(head2);

   if (loop1 == null && loop2 == null) {
      return myNoLoop(head1, head2);
   }else if (loop1 != null && loop2 !=null){
      return myBothLoop(head1, loop1, head2, loop2);
   }
   return null;

}
//Ring node found
public static Node myGetLoopNode(Node head) {
   if (head == null || head.next == null || head.next.next == null)
      return null;
   Node slow = head;
   Node fast = head.next;
   while (fast != slow && fast != null) {
      slow = slow.next;
      fast = fast.next == null ? null : fast.next.next;
   }
   if (fast == null)
      return null;
   fast = null;
   while (fast!=slow){
      fast = fast == null ? head : fast.next;
      slow = slow.next;
   }
   return fast;
}
//Are acyclic
public static Node myNoLoop(Node head1, Node head2) {
   Node p1 = head1;
   Node p2 = head2;
   int s1 = 0;
   int s2 = 0;
   int ds = 0;
   while(p1.next != null) {
      p1 = p1.next;
      s1++;
   }
   while(p2.next != null) {
      p2 = p2.next;
      s2++;
   }
   if (p1 != p2)  // The tail node is different, and null is returned directly
      return null;
   ds = Math.abs(s1 - s2);
   p1 = head1;
   p2 = head2;
   if (s1 >= s2){
      while(ds > 0){
         p1 = p1.next;
         ds--;
      }
   }else {
      while(ds > 0){
         p2 = p2.next;
         ds--;
      }
   }
   while (p1 != p2){
      p1 = p1.next;
      p2 = p2.next;
   }
   return p1;
}
//There are rings
public static Node myBothLoop(Node head1, Node loop1, Node head2, Node loop2) {
   if (loop1 == loop2) {
      Node p1 = head1;
      Node p2 = head2;
      int s1 = 0;
      int s2 = 0;
      int ds = 0;
      while (p1 != loop1) {
         p1 = p1.next;
         s1++;
      }
      while (p2 != loop1) {
         p2 = p2.next;
         s2++;
      }
      ds = Math.abs(s1 - s2);
      p1 = head1;
      p2 = head2;
      if (s1 >= s2) {
         while (ds > 0) {
            p1 = p1.next;
            ds--;
         }
      } else {
         while (ds > 0) {
            p2 = p2.next;
            ds--;
         }
      }
      while (p1 != p2) {
         p1 = p1.next;
         p2 = p2.next;
      }
      return p1;
   }else {
      Node p1 = loop1;
      while (p1 != loop2){
         p1 = p1.next;
         if (p1 == loop1)
            return null;
      }
      return loop1;
   }

}

Tags: Algorithm

Posted on Sat, 06 Nov 2021 06:37:58 -0400 by stylezeca