Linked list
Brief introduction
Hashtable
- Hash table can be understood as a collection structure at the use level
- If there is only key and no accompanying data value, you can use the HashSet structure (called unorderderdedset in C + +)
- If there are both key s and accompanying data value s, you can use the HashMap structure (called unordered map in C + +)
- Whether there is accompanying data value or not is the only difference between HashMap and HashSet. The actual structure of the underlying is the same thing
- Using the operations of put, remove, put and get of the hash table, it can be considered that the time complexity is O(1), but the constant time is relatively large
- If the basic data is put into the hash table, it is passed internally by value, and the memory occupation is the size of this thing
- If the hash table is not the basic data, it is passed internally by reference. The memory occupation is the size of the memory address of the hash table
Ordered table
- The ordered table can be understood as a set structure at the use level
- If there is only key and no accompanying data value, you can use the TreeSet structure (called OrderedSet in C + +)
- If there are both key s and accompanying data value s, you can use the TreeMap structure (called OrderedMap in C + +)
- Whether there is accompanying data value or not is the only difference between TreeMap and TreeSet. The actual structure of the underlying is the same thing
- The difference between an ordered table and a hash table is that an ordered table organizes key s in order, while a hash table is completely inadequate
- Red black tree, AVL number, size balance tree and jump table all belong to ordered table structure, but the specific implementation of the bottom layer is different
- If the basic data is put into the ordered table, it is passed internally by value, and the memory occupation is the size of this thing
- If the items put into the ordered table are not basic data, a comparator must be provided and passed internally by reference. The memory occupation is the size of the memory address of this item
- 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
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)); System.out.println(treeMap1.firstKey() + ", My youngest"); System.out.println(treeMap1.lastKey() + ", My biggest"); 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");
Single linked list, double linked list
Node structure of single linked list
Class Node<V> { V value; Node next; }
Node structure of double linked list
Class Node<V>{ V value; Node next; Node last; }
Reverse linked list
Reverse order
Note whether to add the return value
If there is a header change operation, there must be a return value. If not, it can be defined as void type.
Print the common part of two ordered linked lists
Who is small, who moves, prints equally, and moves together until it exceeds.
Methodology of linked list problem solving in interview
- In the written examination, everything is for the sake of time complexity, and don't care too much about space complexity
- During the interview, try to find the most space-saving method
skill:
1) Additional data structure records (hash table, etc.)
2) Speed pointer
Examples
Question 1
Given the head node of a single linked list, please judge whether the linked list is palindrome structure
Time complexity O(N), additional space complexity O(1)
- Method 1
Put it on the stack and compare the popped one with the original one. If each step is the same, it means palindrome. Otherwise it's not palindrome
- Method 2
Only put the things on the right into the stack. Compare and know that all the things in the stack pop up. If they are the same, it means palindromes. Can save space
(fast and slow pointer) this should be written well
- Method 3
Not applicable to other data structures.
Use two pointers to move from two directions to the center and compare to the center.
Question 2
The single 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
- Method 1
Put it into the array, perform partition, and then string it into a linked list
- Method 2
Define 6 variables
Head and tail SH ST smaller than area
Equal to the head and tail EH ET of the area
Head and tail BH BT larger than area
Be sure to discuss boundaries because there may be no value for a region
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) { //If there is an area smaller than sT.next = eH; eT = eT == null ? sT : eT; //Next, whoever connects the head larger than the area will become eT } //if above, whether running or not, eT // all reconnect if (eT != null) { //If the smaller than area and the equal and area are not all available eT.next = bH; } return sH != null ? sH : eH != null ? eH : bH; }
Question 3
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.
- Method 1
Hash table map
Key - > node type old node, value - > node type new node
Find out the node pointed to by the node through the Map, and then set the node pointed to by the pointer for each copied node.
- Method 2
Do not use hash table
1) The generated clone node is hung on the next node of the old node
2) Then the rand point of the new node is the next point of the old node
3) On next, take out the clone node
Question 4
Given two single linked lists that may or may not have rings, head node head1 and head node 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.
Each node of the single linked list has only one next, so it is impossible to go out of the ring after it is formed. That is, there is only one chain on the ring
- How to find the first ring entry node (first judge whether the linked list has a ring)
- (set a hash table)
At each step, put the values in the linked list into the hash table. When the first node with the same address is encountered, this node is the first ring in node
- (fast and slow pointer method)
Set two pointers, one node at a time (slow pointer) and two nodes at a time (fast pointer). When they meet, the fast pointer returns to the first node at the beginning and becomes a step pointer, and then the node where the two pointers meet again is the first entry point.
public static Node getLoopNode(Node head) { if (head == null || head.next == null || head.next.next == null) { return null; } Node n1 = head.next; // n1 -> slow Node n2 = head.next.next; // n2 -> fast while (n1 != n2) { if (n2.next == null || n2.next.next == null) { return null; } n2 = n2.next.next; n1 = n1.next; } n2 = head; // n2 -> walk again from head while (n1 != n2) { n1 = n1.next; n2 = n2.next; } return n1; }
- Acyclic case
Each node of the single linked list has only one next, so once there is an intersection, the next parts must be shared.
Traverse the first linked list to know the last node, which is counted as end1 and length length1
Traverse the second linked list. The last one is counted as end2 and the length is length2
First judge whether end1 and end2 memories are equal. If they are not equal, there must be no intersection.
Then the long linked list takes the difference step first, and then the two linked lists go together. The meeting node is the first intersection node.
public static Node noLoop(Node head1, Node head2) { if (head1 == null || head2 == null) { return null; } Node cur1 = head1; Node cur2 = head2; int n = 0; while (cur1.next != null) { n++; cur1 = cur1.next; } while (cur2.next != null) { n--; cur2 = cur2.next; } if (cur1 != cur2) { return null; } //n is the length of linked list 1 minus the length of linked list 2 cur1 = n > 0 ? head1 : head2; //Who grows, whose head becomes cur1 cur2 = cur1 == head1 ? head2 : head1; //Short to cur2 n = Math.abs(n); while (n != 0) { n--; cur1 = cur1.next; //Long go first } while (cur1 != cur2) { cur1 = cur1.next; cur2 = cur2.next; } //Walking together, meeting is the intersection node return cur1; }
It is impossible to have a ring, an acyclic, but also intersect
- There are rings
- Each has a ring and does not intersect
If there is a ring and the addresses of the nodes entering the ring are different, loop1 continues to walk once. If loop2 is not encountered, it indicates that there is no intersection. Return null after so long
- The ring in node is the same
There are rings, and the end addresses are found to be equal. Then take the first node into the ring as end, and then use the acyclic method to find the first intersection node.
- Ring in node is not a
If there is a ring and the addresses of the nodes entering the ring are different, loop1 continues to walk once. If loop2 is encountered, it indicates that it is intersected.
At this time, the loop in node of loop1 or loop2 can be returned, which is the first node of intersection
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) { Node cur1 = null; Node cur2 = null; if (loop1 == loop2) { cur1 = head1; cur2 = head2; int n = 0; while (cur1 != loop1) { n++; cur1 = cur1.next; } while (cur2 != loop2) { n--; cur2 = cur2.next; } cur1 = n > 0 ? head1 : head2; cur2 = cur1 == head1 ? head2 : head1; n = Math.abs(n); while (n != 0) { n--; cur1 = cur1.next; } while (cur1 != cur2) { cur1 = cur1.next; cur2 = cur2.next; } return cur1; } else { cur1 = loop1.next; while (cur1 != loop1) { if (cur1 == loop2) { return loop1; } cur1 = cur1.next; } return null; } }
public static Node getIntersectNode(Node head1, Node head2) { if (head1 == null || head2 == null) { return null; } Node loop1 = getLoopNode(head1); Node loop2 = getLoopNode(head2); if (loop1 == null && loop2 == null) { return noLoop(head1, head2); } if (loop1 != null && loop2 != null) { return bothLoop(head1, loop1, head2, loop2); } return null; }