• 建立链表的虚拟头结点 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;
        }
    };
  • 相关阅读:
    MB52增强
    采购订单创建、修改、审批增强ME21N/ME22N/ME28/ME29N
    SAP调用RestfulApi接口POST数据到外部系统
    SAP ABAP: 把内表数据以excel或csv格式,通过前台或者后台的方式上传至FTP服务器
    Docker 入门
    CentOS 扩容
    ubuntu查看防火墙状态
    No module named ds_store
    Django Ajax 实现历史图形查询
    Django 前端BootCSS 实现分页
  • 原文地址:https://www.cnblogs.com/Bella2017/p/10176600.html
Copyright © 2020-2023  润新知