建立链表的虚拟头结点 203 Remove Linked List Element,82,147,148,237

 

 

该逻辑对于删除第一个元素不适用。

这样的代码不优美

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        
        while(head!=NULL && head->val == val){
            ListNode* delNode = head;
            head = delNode ->next;
            delete delNode;
        }
        
        if(head == NULL)
            return NULL;
        
        ListNode* cur = head;
        
        while(cur->next != NULL){
            if(cur->next->val == val){
                //删除
                ListNode* delNode = cur->next;
                cur->next = delNode->next;
                delete delNode;
            }
            else
                cur = cur->next;
        }
        
        return head;
    }
};

 

可以设置一个虚拟的头结点:

 

 

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        
        ListNode* cur = dummyHead;
        
        while(cur->next != NULL){
            if(cur->next->val == val){
                //删除
                ListNode* delNode = cur->next;
                cur->next = delNode->next;
                delete delNode;
            }
            else
                cur = cur->next;
        }
        
        ListNode* retNode = dummyHead->next;
        delete dummyHead;
        return retNode;
    }
};

这道题想了好久,原因是要把重复的所有元素都删除,这里设立一个duplicate标志位来记录当前cur是否与下一个结点重复。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* h = new ListNode(-1);
        h->next = head;
        ListNode* pre = h;
        ListNode* cur = head;
        while(cur!=NULL){
            bool duplicate = false;
            while(cur->next!=NULL && cur->val==cur->next->val){
                ListNode* delNode = cur;
                cur = cur->next;
                delete delNode;
                duplicate = true;
            }
            if(duplicate == false){
                pre = cur;
                cur = cur->next;
            }
            else{
                pre->next = cur->next;
                ListNode* delNode = cur;
                cur = cur->next;
                delete delNode;
            }
        }
        return h->next;
    }
};

 

又重新做了一遍这道题,思路和前面设置标志位记录重复的不太一样。重点在于在两个结点不相同时,需要判断在它们前面是否存在重复的元素,若存在,pre需要跳过这些结点;若不存在,pre直接指向pre->next即cur即可。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head == NULL)
            return NULL;
        ListNode dummy(0);
        dummy.next = head;
        ListNode* pre = &dummy, *cur = head;
        while(cur){
            ListNode* next = cur->next;
            while(next && next->val == cur->val){
                    cur = cur->next;
                    next = next->next;
                }
            if(cur != pre->next){
                cur = next;   //将最后一个重复的跳过
                pre->next = cur;
            }
            else{  //pre和cur之间没有重复的
                pre = cur;
                cur = next;
            }
                
        }
        return dummy.next;
    }
};

 

 

归并两个有序的链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* h = new ListNode(-1);
        ListNode* cur = h;
        ListNode* cur1 = l1;
        ListNode* cur2 = l2;
        while(cur1 != NULL && cur2 != NULL){
            if(cur1->val <= cur2->val){
                cur->next = cur1;
                cur1 = cur1->next;
            }
            else{
                cur->next = cur2;
                cur2 = cur2->next;
            }
            cur = cur->next;
        }
        if(cur1 != NULL){
            cur->next = cur1;
            
        }
        if(cur2 != NULL){
            cur->next = cur2;
            
        }
        ListNode* ret = h->next;
        delete h;
        return ret;
    }
};

 

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* p = dummyHead;
        while(p->next && p->next->next){
            ListNode* node1 = p->next;
            ListNode* node2 = node1->next;
            ListNode* next = node2->next;
            
            node2->next = node1;
            node1->next = next;
            p->next = node2;
            
            p = node1;
        }
        ListNode* ret = dummyHead->next;
        delete dummyHead;
        return ret;
    }
};

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        if(!head || k==1) return head;
        ListNode* dummy = new ListNode(-1);
        ListNode* pre = dummy, *cur = head;
        dummy->next = head;
        int i = 0;
        while(cur){
            i++;
            if(i%k == 0){
                pre = reverseOneGroup(pre, cur->next);
                cur = pre->next;
            }
            else{
                cur = cur->next;
            }
        }
        return dummy->next;
    }
    
    ListNode* reverseOneGroup(ListNode* pre, ListNode* next){
        ListNode* last = pre->next;
        ListNode* cur = last->next;
        while(cur!=next)
        {
            last->next = cur->next;
            cur->next = pre->next;   //注意这里是指向pre->next
            pre->next = cur;
            cur = last->next;
        }
        return last;     //返回需要翻转的最后一个元素
    }
};

用链表来实现插入排序。

思路:创建一个辅助的新链表,并且使用一个指针遍历原链表,每次将原链表中的一个节点插入到新链表的合适位置(即该节点的值大于新链表上的节点的值,又小于后一节点的值)。最后将新链表的头部返回即可。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* insertionSortList(ListNode* head) {
        
        if(head == NULL || head->next == NULL)
            return head;
        
        ListNode* pre = new ListNode(-1), *ans = pre;   //创建一个新链表的头结点,并用一个临时变量来保存
        ListNode* cur = head;  //cur是原链表的指针
        while(cur != NULL){
            //每次循环前重置pre为头结点,保证每次都从头到尾遍历
            pre = ans;
            while(pre->next != NULL && pre->next->val < cur->val){
                pre = pre->next;
            }
            
            //此时,pre->next->val大于cur->val,应把cur插入到pre后
            //保存原链表当前节点的下一个节点
            ListNode* tmp = cur->next;
            //插入cur到pre后
            cur->next = pre->next;
            pre->next = cur;
            
            cur = tmp; //cur在原链表中后移一位
        }
        return ans->next;
    }
};

一样的思路,又写了一遍,创建一个新链表,dummy指向新链表的头结点。扫描原链表,对于每个结点v,从前往后扫描已排序好的结果链表,找到第一个比v大的u结点,将v插入到u之前。

时间复杂度:共遍历n个结点,为每个结点找到合适的位置,最多再遍历n次,所以总的时间复杂度是O(n^2)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* insertionSortList(ListNode* head) {
        ListNode *dummy = new ListNode(-1);   //dummy指向已排序链表的头结点
        
        while(head){
            ListNode* next = head->next;
            ListNode *p = dummy;
            while(p->next && p->next->val <= head->val)
                p = p -> next;  //p->next指向比head大的第一个结点,则p指向比head小的最后一个结点
            //将head插入到p和p->next之间
            head->next = p->next;
            p->next = head;
            
            head = next;
        }
        return dummy->next;
    }
};

 

 

本题适用于归并排序,难点是:怎么样找到分治时的middle指针,采用快慢指针的思想。快指针一次走两步,慢指针一次走一步,当快指针走到头时,慢指针刚好走到中间位置,此位置即为middle的位置。

快慢指针思想:

 快慢指针是指指针移动的步长,快指针移动的快,慢指针移动的慢,例如可以让快指针一次移动两个步长,让慢指针一次移动一个步长。

快慢指针有两个比较重要的应用:

1、判断链表是否为单链表

2、在有序链表中寻找中位数

/**
 * 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 || !head->next) return head;
        ListNode* slow = head, *fast = head, *pre = head;
        while(fast && fast->next){
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = NULL;
        return merge(sortList(head), sortList(slow));
    }
    
    ListNode* merge(ListNode* l1, ListNode* l2){
        ListNode* dummy = new ListNode(-1);
        ListNode* cur = dummy;
        while(l1 && l2){
            if(l1->val < l2->val){
                cur->next = l1;
                l1 = l1->next;
            }
            else{
                cur->next = l2;
                l2 = l2->next;
            }
            cur = cur->next;
        }
        if(l1) cur->next = l1;
        if(l2) cur->next = l2;
        return dummy->next;
    }
};

改变节点的值来解决问题。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void deleteNode(ListNode* node) {
        if(node == NULL)
            return;
        if(node->next == NULL){
            delete node;
            node = NULL;
            return;
        }
        node->val = node->next->val;
        ListNode* delNode = node->next;
        node->next = delNode->next;
        delete delNode;
        return;
    }
};

 

posted @ 2018-12-25 21:31  爱学英语的程序媛  阅读(225)  评论(0编辑  收藏  举报