List
- Basic
- 1. Reverse list (important)
- 2. merge the two sorted list (important)
- 3. The print head from the end of the list
- 4. penultimate linked list node k (important)
- The replication complex list
- 6. Delete list node
- 7. Delete duplicate node list
- 8. singly linked list a series of problems that intersect (important !!!)
- 9. Print ordered list of two common portion
- 10. The list is determined whether a palindrome
- 11. The list is divided about section
- 12. The single list two lists to generate a sum
Basic
0.1 Routine
Written test, do not care about the space complexity, various auxiliary structures directly on, the sooner the better to write
the interview, the pursuit of time complexity O (n) space complexity O (1)
0.2 Basic Operation (represented, insert, delete)
Said insert, delete
struct listnode{
int val;
listnode *next;
listnode(int _val,listnode *_next): val(_val),next(_next){}
}; //表示
p->next = p->next->next; //删除了p-》next
copy_cur = new node(cur->label);
copy_cur->next =cur->next;
cur->next = copy_cur; //这3步插入新节点 插在cur之后
tips: when it comes to the delete operation, we must consider the empty table, delete the header, at moderate operating table
Pointer p1 slow down a fast step 2 steps down the pointer p2
node *p1 = root;
node *p2 = root;
while(p2->next && p2->next->next){
p1 = p1->next;
p2 = p2->next->next;
}
The effect is p1 went to the midpoint, if the total number is an even number p1 came to the middle of the first two, p2 came to a final one
, if the total number is an odd number, came to the middle of the p1, p2 came to the last one.
1. Reverse list (important)
Title Description
After entering a list inverted list, the new list of the output header. (Source prove safety offer 24) (non-head node)
a) iteration ideas
Idea: We want to modify the next pointer member of each node, so every time to modify the current cur the next, pointing to pre (so remember pre), and also to remember the next node cur.
Method Memory : pre, cur, after three pointers.
Code
//第一种方法是:非递归方法
//设计好代码后 要考虑的特殊情况nullptr 一个节点 多个节点
listnode *reversenode(listnode *phead){
listnode *pre=nullptr, *cur=phead, *after = nullptr;
while(cur != nullptr){
after = cur->next; //保存当前的下一个
cur->next=pre; //调整当前next
pre = cur; //前一个前进
cur= after; //当前前进
}
return pre;
}
b) recursive method
tips: do not clever, so easy. Big problems, small problems, and do their own thing on the ojbk
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
//如果链表为空或者链表中只有一个元素
if(pHead==NULL||pHead->next==NULL) return pHead;
//先反转后面的链表,走到链表的末端结点
ListNode* pReverseNode=ReverseList(pHead->next);
//再将当前节点设置为后面节点的后续节点
pHead->next->next=pHead;
pHead->next=NULL;
return pReverseNode;
}
};
It has a head node
Nothing special, is to first check the head node is empty it, and then let the head of the list after the head node point reversal
listnode *reversnode2(listnode *phead){
if(!phead)
return phead;
listnode *pre=nullptr, *cur=phead->next, *after = nullptr;
while(cur != nullptr){
after = cur->next; //保存当前的下一个
cur->next=pre; //调整当前next
pre = cur; //前一个前进
cur= after; //当前前进
}
phead->next = pre;
return phead;
}
Reverse doubly linked list
There is no special, we know there is such a thing, next pointer and two members of the pre-exchange on the line
2. merge the two sorted list (important)
Title Description
Two monotonically increasing input list and output list after synthesis of two lists, of course, after that we need to meet synthesis list - decreasing the rules. (Source prove safety offer 25)
Iterative version of the idea
We need three pointers, pointer a, b is used to track the two lists, a pointer used to point c after the last node in the list, we merge, so that when we compare a, b point node size, so that the next point c the result of the comparison, you can. If there is a linked list in the end, then the list directly to the other element added to the combined list. In the specific implementation process, we puppet node (common trick the list), root to operate by a set, its role is to allow the synthesis of new chain has a place to start. The value of this node are free, we finally returned, in fact root.next;
Code
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
using node = ListNode;
//新建一个头节点,用来存合并的链表。
node root = node(0);
node *cur = &root;
while(pHead1 && pHead2){
if(pHead1->val < pHead2->val){
cur->next=pHead1;
pHead1=pHead1->next;
} else{
cur->next=pHead2;
pHead2 = pHead2->next;
}
cur=cur->next;
}
//把未结束的链表连接到合并后的链表尾部
if(pHead1)
cur->next=pHead1;
if(pHead2)
cur->next=pHead2;
return node.next;
}
};
Recursive version ideas
Compare two head node size to give a true head node phead (smaller), then recursively processing small problem, plus some operations (the result phead the big problem with the results of small problems all together, return phead, recursive If the outlet of which one node is empty, return directly to the other)
Code
//递归版本 //
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(!pHead1)
return pHead2;
if(!pHead2)
return pHead1;
ListNode* p=nullptr;
if((pHead1->val)< (pHead2->val)){
p=pHead1;
p->next = Merge(pHead1->next,pHead2);
}
else{
p=pHead2;
p->next = Merge(pHead1,pHead2->next);
}
return p;
}
};
3. The print head from the end of the list
Title Description
Enter a list, the value returned by a ArrayList list sequentially from the tail to the head. (Source prove safety 6)
Thinking
Using the stack (simple question)
Code
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
stack<int> sta;
vector<int> res;
while(head){
sta.push(head->val);
head=head->next;
}
while(!sta.empty()){
res.push_back(sta.top());
sta.pop();
}
return res;
}
};
4. penultimate linked list node k (important)
Title Description
Input a linked list, the linked list output reciprocal k-th node. (Source prove safety 22)
simple but important
Thinking
Pointer speed, note the inverse of the k-th node, the pointers go fast step k-1, instead of k steps, and k = 0 Note that the boundary problem head and a null pointer, there is the case if the length of the list is less than k
Code
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
// 认为k==0是个无效的东西
if(!pListHead || k==0)
return nullptr;
using node = ListNode;
node * cur= pListHead;
for(int i=0;i<k-1 && cur;++i){
cur=cur->next;
}
//链表的长度小于k的情况
if(!cur)
return nullptr;
//想象一下k=1 可以写出代码
node * res = pListHead;
while(cur->next){
cur=cur->next;
res=res->next;
}
return res;
}
};
The replication complex list
Title Description
A complex input list (each node has a node value, and two pointers, one pointing to the next node, a special pointer to any other node), returns a value after the head of the list replication complex. (Note that the output results do not return parameter node reference, otherwise the program will return empty sentenced questions directly) (Source prove safety 35)
Thinking
Two solutions:
1. memory hash table
2. The chain double, setting the pointer, and finally disconnected.
@ 1 Solution: Hash time O (n) space O (n) //
twice traversed.
Traversing each node of the first copy, and put together with the hash table.
The second pass, took the copy associated set of random next copy
Hash code
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(!pHead)
return nullptr;
using node = RandomListNode;
unordered_map<node*,node *> dict;
node *cur=pHead;
while(cur){
dict.insert({cur,new node(cur->label)});
cur=cur->next;
}
cur=pHead;
while(cur){
dict[cur]->next=dict[cur->next];
dict[cur]->random=dict[cur->random];
cur=cur->next;
}
return dict[pHead];
}
};
Solution 2 code
- Traversing the nodes, each gave a value interpolated back to exactly the same as the new node
- This once again traverse the node and then two steps, the random gave each new node to get
- Finally, the list to open. (Note that several boundary conditions)
time O (n) space O (1)
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead ==nullptr)
return nullptr;
return core1(pHead);
}
//让原链表 double
RandomListNode* core1(RandomListNode* pHead){
using node = RandomListNode;
node * cur = pHead;
node* copy_cur=nullptr;
while(cur){
copy_cur = new node(cur->label);
copy_cur->next =cur->next;
cur->next = copy_cur; //这3步插入新节点
cur = copy_cur->next; //向下走
}
//复制节点的 random
cur = pHead;
copy_cur = pHead->next;
while(cur){
if(cur->random){ //避免random指向空
copy_cur->random = cur->random->next;
}
cur = copy_cur->next;
if(cur != nullptr) // 再次注意边界
copy_cur = cur->next;
}
//拆分链表
cur = pHead;
copy_cur = pHead->next;
node * copy_head = copy_cur;
while(cur){
//cur和copy的拆分都需要!
cur->next = copy_cur->next; //拆 cur
cur = cur->next; // cur往下移动
if(cur != nullptr) // 注意边界
copy_cur->next = cur->next; // 拆copy
copy_cur =copy_cur->next; // copy移动
}
return copy_head;
}
};
6. Delete list node
Title Description
Order to delete the node to the head pointer list and a node pointer in O (1) time (to prove safety source 18)
Thinking
Because the requirements are O (1), and is a singly linked list, it is proposed a new method for "replacing"
- If the node is not the end node, then the value may be directly assigned to a node of the node, then enabling the next node pointing to the next node, the next node is deleted, the time complexity is O (1).
- If it is the end node, but the entire list, only this one node, then delete
- If you list more than one node, you need to traverse the list to find the previous node, and then let a node point before nullptr, and then delete, time complexity is O (N).
ps. After delete, do not forget to set nullptr (to regulate)
Code
void core(node **head,node *del ){
//如果是空指针
if(!head || !del)
return;
//要删除的del不是尾结点
if(del->next){
node * res =del->next;
del->val=res->val;
del->next=res->next;
delete res;
res=nullptr;
}
else if(*head ==del){ // 只有这一个指针
delete del;
del=nullptr;
*res=nullptr;
}
else{ // 有多个节点,并且是尾结点,遍历找到前一个
node *cur = *head;
while(cur->next != del){
cur=cur->next;
}
cur->next=nullptr;
delete del;
del=nullptr;
}
}
7. Delete duplicate node list
a) retain the version
Title Description
In a sorted linked list nodes duplicate, delete the duplicate node list, the node repeats a reservation, the head pointer list returned. For example, list 1-> 2-> 3-> 3-> 4-> 4-> 5 workup 1-> 2-> 3-> 4-> 5
tips: This is a reserved version, and sorted the
Thinking
A pre nodes and the current node node traversal save on cur
- If the current node and a node on the same value, then a delete operation is performed on cur does not advance and pre, cur proceeds.
- If the two are different forward
Code
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(!pHead) return nullptr;
ListNode* pre = pHead;
ListNode* cur = pHead->next;
while(cur){
if(pre->val==cur->val){
pre->next = cur->next;
cur=cur->next;
}
else{
pre =cur;
cur=cur->next;
}
}
return pHead;
}
};
b) does not retain version
Title Description
In a sorted linked list nodes duplicate, delete the duplicate node list, the node does not retain repeated, returns the head pointer list. For example, the list 1-> 2-> 3-> 3-> 4-> 4-> 5 is treated 1-> 2-> 5
tips: This version is not retained, still sorted the
Iteration
Because there duplicate nodes should be deleted, so it is possible to head node must be deleted.
So for convenience, we first let's add a puppet node root, in order to facilitate the first encounter, the second node on the same situation
and we have been directed to ensure that p is not a repeat of the last node, so we let p point to root, traversing
- If p- "val next of == p-" next- "next of val, then began to eliminate, we write down the value of dup, deleted until p-" next val is not equal to dup or equal nullptr the next date
- If unequal, then p to move back
Code
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
using node = ListNode;
if(!pHead || !pHead->next)
return pHead;
node temp(0);
node *root=&temp;
root->next=pHead; // 首先添加一个傀儡节点,以方便碰到第一个,第二个节点就相同的情况
node *p=root;
int dup;
while(p->next && p->next->next){
//如果当前cur有下一个 且下一个跟cur值一样,那么
if(p->next->val== p->next->next->val ){
dup=p->next->val;
while(p->next && p->next->val== dup){
p->next=p->next->next; //直到p-》next的val是个新值为止 or 指向nullptr。
}
}
else p=p->next;
}
return root->next;
}
};
Recursive version
Well understood
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
// 只有0个或1个结点,则返回
if(!pHead || !pHead->next)
return pHead;
// 当前结点是重复结点
if(pHead->val == pHead->next->val){
ListNode * cur = pHead->next;
while(cur && cur->val == pHead->val){
cur =cur->next;
}// 跳过值与当前结点相同的全部结点,找到第一个与当前结点不同的结点
return deleteDuplication(cur);
// 从第一个与当前结点不同的结点开始递归
}
// 当前结点不是重复结点
else{
// 保留当前结点,从下一个结点开始递归
pHead->next = deleteDuplication(pHead->next);
return pHead;
}
}
};
8. singly linked list a series of problems that intersect (important !!!)
Two-way linked list, find the first point of intersection, which is actually three questions !!!
- How to determine whether there is a chain ring and find the entrance ring
- How to find the node 2 single chain acyclic first intersection
- How to find the two rings have a single list of intersection node
tips: (if there is a ring, a loop-free, two-way linked list (as a singly linked list) may not intersect)
Here just write ideas: a complete analysis
Question 1: How to determine whether there is a chain ring and ring to find the entrance of
a slow go one step each time the pointer p1, p2 pointer to a fast walk every step 2, if no ring, fast pointer is necessarily the end of next encounter is nullptr, that direct return nullptr, if there is a ring that p1 and p2 will definitely meet in the ring in a location. This time the pointer quickly back into position at the beginning of the list, and each time step, while slow pointer also go one step further from that encounter each position, the last two pointer position must meet the entrance ring
Question 2: How to find the node 2 single chain acyclic first intersect?
Two single chain acyclic, if the intersection, it can be Y-shaped
so the process is to find
the list to the end of a traversing node end1, while the recording dots len1 summary
list traversal to the end node end2 2, while the recording dots are summarized len2
Comparative end1 and end2, nullptr a return are not equal, the next step is equal to enter
the large len list, if the list is 1, go len1-len2 step,
then go with two lists, one of the two nodes is equal to the first result is a first intersecting nodes.
Question 3: How to find the two rings have a single list of the first intersection node?
Divided into three cases
1) two inlet rings are equal then the overall shape of a Y + ring,
this problem just like the case 2, similar to the first two acyclic intersection node, but now is the inlet end of the ring
2) two inlet rings unequal, and two disjoint lists,
ranging from the inlet 3) of the two rings, but the intersection of two lists, that is, from the shape of a ring topology, the separation of the two lines, so that the first intersection point is any one of two inlet rings
9. Print ordered list of two common portion
Only ideas
The process is similar to merge, starting from their starting point, which is a small value, step forward, it is the same as print
(source left God)
10. The list is determined whether a palindrome
Title Description
1221 12331 palindrome is not a palindrome
(Source left God)
Thinking
Use auxiliary space:
With a stack traverse the list to keep the value on the stack
and then traverse a linked list while compare with the top element, not the same as it returns false, as the pop-up, a relatively lower
Without the use of auxiliary space:
Fast take two steps pointer, pointer slow step, to the intermediate position of that node, and the node to which a half after the reversal, and start from both ends of the comparison, the same one, the false different ratio, while the final it reversed back to the second half of the node.
java代码
// 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;
}
11. The list is divided about section
Title Description
The one-way linked list by a certain value divided into small left, center equal to the right of the large form
(source left God)
Thinking
Auxiliary space
Array put it back again inside the partition and then a series (or directly in the original list to which the changed values).
Without the use of auxiliary space
6 to change the pointer respectively corresponding to less equal more
start and end points, then traverse the list, the respective nodes fill it up, the last three zones joined end to end
12. The single list two lists to generate a sum
Title Description
937 and 63 generate 1000
(left God source)
Thinking
A method string into two strings 93763 obtained by adding 1000 to generate the list (the number is too large to prevent the string, int overflow)
method of directly adding 2 reverse two lists, then the new list in reverse order, to