例题一:链表逆序 leetcode206
已知链表头结点指针head,将链表逆序。(不可申请额外空间)
依次遍历链表节点,每遍历一个节点即逆置一个节点
ListNode *reverseList(ListNode * head){
ListNode* new_head = NULL;
while(head){
ListNode * next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
return new_head;
}
第二题:已知链表头结点指针head,将链表从位置m到n逆序。(不申请额外空间)Leetcode 92
ListNode *reverseBetween(ListNode* head,int m, int n){
int chang_len = n-m+1; //计算需要逆置的节点数
ListNode *new_head = NULL; //新节点
ListNode *pre_head = NULL; //逆置的前置节点
ListNode *result = head; //最后的节点
while(head && --m){
pre_head = head; //记录head的前置节点
head=head->next;
}
ListNode *list_tail = head; //将head指向当前节点 ,即逆置后的节点
while(head && chang_len){
ListNode *next = head->next;
head->next = new_head;
new_head = head;
head = next;
chang_len--;
}
list_tail->next = head; //将尾部相连
if(pre_head) //如果头结点存在 说明不是从第一个节点开始的
pre_head->next = new_head;
else
result = new_head; //如果pre_head为空,说明m==1从第一个节点开始逆置结果即为逆置后的头结点
return result;
}
第三题:求两个链表的交点
已知链表A的头结点指针headA,链表B的头结点指针headB,两个链表相交,求两链表交点对应的节点。leetcode 160
1.如果两个链表没有交点,则返回NULL
2.再求交点的过程中,不可以破坏链表的结构或者修改链表的数据域
3.可以确保传入的链表A与链表B没有任何环
4.实现算法尽可能使时间复杂度O(n),空间复杂度O(1)
思路1:使用set求交集
1.遍历链表A,将A中节点对应的指针(地址),插入set
2.遍历链表B,将B中节点对应的指针(地址),在set中查找,发现在set中的第一个节点地址,即是两个链表的交点。
ListNode *getIntersectionNode(ListNode *headA,ListNode *headB){
set<ListNode*>node_set;
while(headA){
node_set.insert(headA);
headA=headA->next;
}
while(headB){
if(node_set.find(headB)!=node_set.end())
return headB; //找到交点
headB=headB->headB;
}
return NULL;
}
思路2:空间复杂度O(1)
步骤1:计算headA链表长度、计算headB链表长度,较长的链表多出的长度
2:将较长链表的指针移动到和较短链表指针对齐的位置
3:headA与headB同时移动,当两指针指向同一个节点时,即找到了
int get_list_length(ListNode *head){
int len=0;
while(head){
len++;
head=head->next;
}
return len;
}
ListNode *forward_long_list(int long_len,int short_len,ListNode *head){
int delta = long_len-short_len;
while(head&&delta){
delta--;
head=head->next;
}
return head;
}
ListNode *getIntersectionNode(ListNode *headA,ListNode *headB){
int lenA = get_list_length(headA);
int lenB= get_list_length(headB);
if(lenA>lenB)
forward_long_list(lenA,lenB,headA);
else
forward_long_list(lenB,lenaA,headB);
while(headA&&headB){
if(headA==headB)
return headA;
headA=headA->next;
headB=headB->next;
}
return NULL;
}
第三题:链表求环
已知链表中可能存在环,若有环返回环起始节点,否则返回NULL;leetcode 141
思路1:使用set求环起始节点
1.遍历链表,将链表中节点对应的指针(地址),插入set
2.在遍历时插入节点前,需要在set中查找,第一个在set中发现的节点地址,即是链表环的起点
ListNode *detectCycle(ListNode *head){
set<ListNode *>node_set;
while(head){
if(node_set.find(head)!=node_set.end())
return head; //返回环的第一个节点
node_set.insert(head);
head=head->next;
}
return NULL; //没有遇到环,则返回NULL;
}
思路2:快慢指针赛跑
ListNode *detectCycle(ListNode *head){
ListNode *fast = head;
ListNode *slow = head;
ListNode*meet = NULL;
while(fast){
slow = slow->next;
fast = fast->next;
while(!fast){
return NULL;
}
fast=fast->next;
if(fast==slow){
meet=fast;
break;
}
}
while(meet&&head){
if(meet==head)
return meet;
meet=meet->next;
head=head->next;
}
return NULL;
}
第四题:链表划分:
已知链表头指针head与数值x,将所有小于x的节点放在大于或等于x的节点前,且保持这些节点的原来的相对位置。Leetcode 86
思路:使用两个临时节点less_ptr和more_ptr;将节点值大于x的放置在more_ptr后面,小于x的放置在less_ptr后面,最后将less_ptr的尾节点和more_ptr的头结点相连即可。
ListNode *parition(ListNode *head,int x){
ListNode less_head(0);
ListNode more_head(0);
ListNode *less_ptr = &less_head;
ListNode *more_ptr=&more_head;
while(head){
if(head->val < x){
less_ptr->next = head;
less_ptr = head;
}
else {
more_ptr->next = head;
more_ptr = head;
}
head = head->next;
}
less_ptr->next = more_head.next;
more_ptr->next = NULL;
return less_head.next;
}
第五题:排序链表的合并 leetcode 21
a:已知两个已排序链表头节点指针l1与l2,将这两个链表合并,合并后仍为有序的,返回合并后的头节点。
思路:比较l1和l2指向的节点,将较小的节点插入到pre指针后,并向前移动较小节点对应的指针
ListNode *mergeTwoLists(ListNode* l1,ListNode* l2){
ListNode temp_head(0);
ListNode *pre = &temp_head;
while(l1 && l2){
if(l1->val < l2->val){
pre->next = l1;
l1=l1->next;
}
else {
pre->next = l2;
l2=l2->next;
}
pre = pre->next;
}
if(l1)
pre->next = l1;
if(l2)
pre->next = l2;
return temp_head.next;
}
b:已知k个已排序链表头节点指针,将这k个链表合并,合并后仍为有序的,返回合并后的头节点。leetcode 23
思路:将k*n个节点放到vector中,再将vector排序,再将节点顺序相连。
bool cmp(const ListNode *a,const ListNode *b){
return a->val < b->val;
}
ListNode *mergeKists(vector<ListNode*>& lists){
vector<ListNode *>node_vec;
for(int i=0;i<lists.size();i++){
ListNode *head = lists[i];
while(head){
node_vec.push_back(head);
head=head->next;
}
}
if(node_vec.size()==0) return NULL;
sort(node_vec.begin(),node_vec.end(),cmp);
for(int i=0;i<node_vec.size();i++)
node_vec[i-1]->next = node_vec[i];
node_vec[node_vec.size()-1]->next = NULL;
return node_vec[0];
}
ListNode *mergeKists(vector<ListNode*>& lists){
if(list.size()==0) return NULL;
if(lits.size()==1) return lists[0];
if(lists.size()==2) return mergeTwoLists(lists[0],lists[1]);
int mid = lists.size()/2;
vector<ListNode*> sub1_lists;
vector<ListNode*> sub2_lists;
for(int i=0;i<mid;i++)
sub1_lists.push_back(lists[i]);
for(int i=mid;i<lists.size();i++)
sub2_lists.push_back(lists[i]);
ListNode *l1 = mergeKLists(sub1_lists);
ListNode *l2 = mergeKLists(sub2_lists);
return mergeTwoLists(l1,l2);
}