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; } }