Intersection of Two Linked Lists | 28.9% | |||
Sort List | 2013-11-16 | 20.8% | Medium | |
Insertion Sort List | 2013-11-12 | 25.4% | Medium | |
Reorder List | 2013-11-02 | 20.5% | Medium | |
Linked List Cycle II | 2013-10-30 | 30.8% | Medium | |
Linked List Cycle | 2013-10-28 | 35.9% | Medium | |
Copy List with Random Pointer | 2013-10-03 | 23.6% | Hard | |
Flatten Binary Tree to Linked List | 2012-10-14 | 28.2% | Medium | |
Convert Sorted List to Binary Search Tree | 2012-10-02 | 27.4% | Medium | |
Reverse Linked List II | 2012-06-27 | 26.1% | Medium | |
Partition List | 2012-04-30 | 27.0% | Medium | |
Remove Duplicates from Sorted List II | 2012-04-22 | 24.8% | Medium | |
Remove Duplicates from Sorted List | 2012-04-22 | 34.6% | Easy | |
Merge Two Sorted Lists | 2012-03-30 | 33.1% | Easy | |
Rotate List | 2012-03-27 | 21.9% | Medium | |
Merge k Sorted Lists | 2012-02-13 | 21.0% | Hard | |
Remove Nth Node From End of List | 2012-01-27 | 28.9% | Easy |
Intersection of Two Linked Lists
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * p=headA, *pp=NULL, *q=headB, *pq=NULL, *tmp;
int i = 0; while(p) i++, pp = p, p=p->next;
int j = 0; while(q) j++, pq = q, q=q->next;
if(pp!=pq) return NULL;
if(i<j) tmp = headA, headA = headB, headB = tmp;
for(int k = 0; k<abs(i-j); k++) headA=headA->next;
while(headA!=headB) headA=headA->next, headB=headB->next;
return headA;
}
};
sort list
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *sortList(ListNode *head) {
if(!head) return head;
return sort(head, NULL);
}
ListNode* sort(ListNode *l, ListNode *r){
// assert(l != NULL);
if( l ->next == r ) {
l->next = NULL;
return l;
}
ListNode *p=l, *p2=l;
while(p2 != r && p2->next != r){
p=p->next; p2=p2->next->next;
}
ListNode *a, *b, *head = NULL, *tail = NULL;
a = sort(l, p);
b = sort(p, r);
while(a != NULL && b != NULL ){
if( a->val > b->val ) {ListNode *tmp = a; a = b; b = tmp; }//@error
if(!head) head = a;
if(tail) tail -> next = a;
tail = a;
a=a->next;
}
if( a!= NULL ){
if(!head) head = a;
if(tail) tail -> next = a;
}
if( b!= NULL){
if(!head) head = b;
if(tail) tail -> next = b;
}
return head;
}
};
上述代码要注意
while(p2!=r && p2->next!=r){
p=p->next; p2=p2->next->next;
}
这里p = mid 指向了中点(l+r)/2,注意r是不包括在内的,而 p2 指向了左闭右开 【l, r) 区间的最后一个元素,或者r。注意如果把【l,r)改写成全闭区间【L,R], 那么上面的运算的结果mid=( L + R+1)/2。总之mid实际上是中间偏右的一个点,不是纯正的中点。
在此基础上,就可以二分成: sort(l, r) => sort(l, p), sort(p, r) ([l, r) => [l, (l+r)/2), [(l+r)/2, r) )
上述代码还可以优化: 对于当前链表<head, tail>,向后链入元素a,只需要以下三句:
if(!head) head = a;
else tail -> next = a;
tail = a;
是不是逻辑很清晰?
我们就把上面三句话构成的append方法叫做 head-tail-append吧。
基数排序
上题也可以基数排序,毕竟保存的都是数嘛。注意弄19个链表<lists[i], tails[i]>;
从个位往高位依次排序,重复下面过程:
- 遍历<lst, tail>中的节点it,append该节点到该位(-9 ~ 9)对应的链表<lists[i], tails[i]> 中;
- 置<lst, tail> 为<NULL, xx>,即清空。
- 从9到-9依次把<lists[i], tails[i]>append到<lst, tail> 中。
- 置<lists[i], tails[i]>为<NULL, xx>,即清空。
下面是非常漂亮的一段实现代码。
ListNode *sortList(ListNode *head) {
ListNode* lsts[19];//-9~9
ListNode* tails[19];
typedef ListNode* PNode;
ListNode* lst=head,*tail;
if(lst==NULL) return NULL;
//基数排序
int d=1;
while(d<0xfffffff){
for(int i=0;i<19;i++) lsts[i]=NULL;
for(PNode it=lst;it!=NULL;it=it->next){
int s=9+(it->val/d)%10;//0~18
// head-tail-append 三句代码,append 节点it
if(!lsts[s]) lsts[s]=it;
else tails[s]->next=it;
tails[s]=it;
}
lst=NULL; // <lst, tail> inited as <NULL, xx>
for(int i=0;i<19;i++){
if(lsts[i]){
// head-tail-append 三句代码再次出现
if(!lst) lst=lsts[i],tail=tails[i];
else tail->next=lsts[i],tail=tails[i];
}
}
tail->next=NULL;
d*=10;
}
return lst;
}
把链表转成平衡二叉树
步骤和上面类似:
1 二分 dfs(l, r):
- 如果 l==r, 空区间 返回NULL
- 如果 l->next == r, 返回一个节点
- 否则 找 mid ,以mid为根节点, 二分为 dfs(l, mid), dfs(mid->next ,r)
寻找mid的方法(下面方法找到的mid偏右)
p1 = l, p2 = l;
while(p2 !=r && p2->next !=r){
p1 = p1->next, p2 = p2->next->next;
} //p1 将指向[l, r) 中的(l+r)/2
//一定要记得二分法中mid=(l+r)/2的含义:
// 示意图:# # * # #, 或者 # * #
// 区间对应[l, r] 或 [l, r)
TreeNode *convert(ListNode *l, ListNode *r){
if(l == r) return NULL;
if(r == l->next) return new TreeNode(l->val);
ListNode *mid=l, *p2 = l;
while(p2 != r && p2->next != r){
mid = mid->next, p2 = p2->next->next;
}
TreeNode *lt = convert(l, mid), *rt = convert(mid->next, r);
TreeNode *p = new TreeNode(mid->val);
p->left = lt, p->right = rt;
return p;
}
或者用计数法找中点mid,则n=区间节点个数,区间[0, n-1]的中点mid的下标为( 0 + n-1 ) / 2, 用 pm = left; for(i=0; i<mid; i++) pm = pm->next;即可得到中央节点pm
TreeNode *dfs(ListNode *left,int n){
if(n<=0) return NULL;
ListNode *mid=left;
for(int i=0;i<(n-1)/2;i++) mid=mid->next;
TreeNode *node=new TreeNode(mid->val);
TreeNode *pl=dfs(left,(n-1)/2),*pr=dfs(mid->next,n/2);
node->left=pl,node->right=pr;
return node;
}
删除倒数第k个节点
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head, int n) {
ListNode *p=head,*pre = NULL, *q = head;
int i = 1; for(; i<n && q; i++) q = q->next;
if(i==n){
while(q->next) pre = p, p = p->next, q = q->next;
if(!pre){
head = head -> next;
}
else pre->next = pre->next->next;
free(p);
}
return head;
}
};
或者
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head, int n) {
ListNode *p=head,*pre;
int i;for(i=0;p!=NULL;i++){ p=p->next;} //i=size
if(n>i||n<=0) return head;
n=i-n; //point[n]
pre=head;
for(i=0;i<n-1;i++) pre=pre->next;
if(n-1<0) {head=head->next; return head;}
pre->next=pre->next->next;
return head;
}
};
划分List (小于x | 大于等于x)
class Solution {
public:
ListNode *partition(ListNode *head, int x) {
ListNode *p=head,*pre=NULL;
while(p!=NULL&&p->val<x){ pre=p,p=p->next;}
if(p!=NULL){//p->val>=x
ListNode *q=p->next,*preq=p;
while(q!=NULL){
if(q->val<x){
//cut q and insert before p
preq->next=q->next;
if(pre!=NULL) {pre->next=q;}
else {head=q;}//head change
q->next=p;
pre=q;
}
preq=q,q=q->next;//@attention: not good
}
}
return head;
}
};
或者
class Solution {
public:
ListNode *partition(ListNode *head, int x) {
ListNode * p = head, *pp = NULL;
while(p && p->val < x) pp = p, p = p->next;
if(p){
ListNode * q = p->next, * pq = p;
while(q){
if( q->val < x )
{
pq -> next = pq->next->next;
if(!pp) head = q;
else pp -> next = q;
pp = q;
pp -> next = p;
q = pq -> next;//@important
}
else pq = q, q = q->next;
}
}
return head;
}
};
copy list with random pointer
整体上分为三步骤:
第一步对每个节点拷贝一个新的跟在后面,
第二步非常重要:在这里而不是在后面修改新节点的random指针,并且注意“空指针”
第三步,拆分原有链表和新增链表(用p1,q1分别表示新增表头尾指针即可)。用到了上述的head-tail-append三句代码。
/**
* Definition for singly-linked list with a random pointer.
* struct RandomListNode {
* int label;
* RandomListNode *next, *random;
* RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
* };
*/
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
RandomListNode * p = head, *np;
while(p){
RandomListNode * t = new RandomListNode(p->label);
t->random = p->random;
t->next = p->next;
p->next = t;
p = t->next;
}
//@error: should change random below, not later
p = head;
while(p){
np = p->next;
if(np->random) np->random = np->random->next;
p = np->next;
}
p = head;
RandomListNode *p1=NULL, *q1;
while(p){
np = p->next;
// if(np->random) np -> random = np->random->next; //@error: should be changed earlier
if(p1) q1->next = np;
else p1 = np;
q1 = np;
p -> next = np->next;
p = p -> next;
}
return p1;
}
};
链表插入排序
步骤:
- 将p->next 置为NULL,准备插入(此外np记录下一个p)
- 如果pre==NULL,说明q=head, p将插入到<head, NULL>之前,于是头部插入, p替代head (p->next=head, head=p;)
- 否则, 在<head, NULL> 中间或末尾插入,如果在末尾则q为NULL (pre->next = p, p->next = q; )
class Solution {
public:
ListNode *insertionSortList(ListNode *head) {
if(!head) return head;
ListNode *q =NULL, *pre = NULL, *p = head->next, *np;
head -> next = NULL;
while(p){
np = p->next;
p->next = NULL; // cut p
pre = NULL, q = head;
while(q && q->val <= p->val) pre = q, q = q->next;
if(!pre) p->next = head, head = p;
else p -> next = pre -> next, pre->next = p;
p = np;
}
return head;
}
};
Reorder List
只想到了O(n)空间复杂度的解法。有O(1)空间的解法吗?
void reorderList(ListNode *head) {
if(!head) return;
vector<ListNode *> vec;
ListNode * p =head;
while(p) vec.push_back(p), p = p->next;
int n = vec.size();
for(int i = 0; i<=(n-1)/2; i++){
if(i>0) vec[n-i]->next = vec[i];
vec[i]->next = vec[n-1-i];
vec[n-1-i]->next = NULL;
}
}
Remove Duplicate 2
class Solution {
public:
ListNode *deleteDuplicates(ListNode *head) {
ListNode * pre = NULL, * p = head, *np;
head = NULL; // <head, pre> inited to <NULL, xx>
while(p){
ListNode * q = p->next, *tmp;
while(q && q->val == p->val) q = q->next;
// append p to <head, pre>
if(q==p->next){
p->next = NULL;
if(!pre) head = p;
else pre->next = p;
pre = p;
}
//skip duplicated p
else{
while(p!=q) {
ListNode *tmp = p->next;
free(p);
p = tmp;
}
}
//next p
p = q;
}
return head;
}
};
或者
保持左边<head, pre>和右边的p的链接。
ListNode *deleteDuplicates(ListNode *head) {
ListNode *p=head,*pre=NULL;
while(p!=NULL&&p->next!=NULL){
if(p->val==p->next->val){
int val=p->val; ListNode *next;
while(p!=NULL&&p->val==val){
next=p->next;
delete p;
p=next;
}
// <head, pre> link to next p
if(pre!=NULL) pre->next=p;
else { head=p; }
}
else{
// p append to <head, pre>
pre=p,p=p->next;
}
}
return head;
}
};
swap pairs
注意np,pp分别代表什么
ListNode *swapPairs(ListNode *head) {
ListNode * p = head, *q = p, *np, *pp = NULL;
while(p && p->next){
np = p->next->next;
q = p->next;
q -> next = p;
// link last section with q
if(pp) pp -> next = q;
// first section, then head change
else head = q;
pp = p, p = np;
}
// link last section with p=NULL or single element
if(pp) pp->next = p;
return head;
}
rotate list
这个题目比较坑爹的地方在于k的大小可以超过n,
记得shift k相当于把下标为(n-k%n)%n的元素给作为首节点,就OK了
ListNode *rotateRight(ListNode *head, int k) {
int n =0;
ListNode * p = head, * pre = NULL, *tail = NULL;
while(p){ n++; tail = p, p = p->next; }
if(n==0) return head;
k = (n - k%n)%n;
if(k==0) return head;
p = head;
for(int i=0; i<k; i++){ pre = p, p = p->next; }
tail -> next = head, head = p, pre -> next = NULL;
return head;
}
add two numbers
非常优美的,从第一个节点汪最后一个节点计算和append:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
// @error: no need to reverse l1 or l2
/*ListNode * p = l2, *pp =NULL;
while(p){
ListNode *np = p->next;
p->next = pp;
pp = p, p = np;
}
l2 = pp;*/
ListNode * l3 = NULL, *tail;//head
int c =0;
while(l1 || l2 || c){
int a= l1? l1->val:0;
int b = l2? l2->val:0;
if(l1) l1 = l1->next;
if(l2) l2 = l2->next;
int t = a + b + c;
if(t>=10) t%=10, c=1;
else c = 0;
ListNode * tmp = new ListNode(t);
//tmp->next = l3, l3 = tmp; //@error: should not insert in the head of <l3, xx>, because head is the lowest bit
if(!l3) l3 = tmp; //@attention: should append tmp to <l3, tail>
else tail->next = tmp;
tail = tmp;
}
return l3;
}