LeetCode笔记(链表的归并排序***,二分查找***,快慢指针*** )

坚持就是胜利! 奥利给!

148. 排序链表 - medium

在这里插入图片描述
排序都是用自带sort,而且这还是第一次写链表的归并,所以慢的不行。。。
链表的归并需要注意,每次找到中点后都要让中点前一点的next = nullptr,不然没有递归出口。

//19.58
//20.48
//其实看了答案后才想到这并不是空间复杂度为O(1),因为递归要栈空间
class Solution {
    void mergeSort(ListNode* &head) {
        if(head == nullptr) return ;
        if(head->next == nullptr) return ;

        ListNode *slow, *fast, *curr;
        fast = slow = curr = head;
        while(fast) {
            slow = curr;
            curr = curr->next;
            fast = fast->next;
            if(fast) fast = fast->next;
        }
		/*都一样的
		while(fast && fast->next) {
			slow = curr;
			curr = curr->next;
			fast = fast->next->next;
		}
		*/
        slow->next = nullptr;
        mergeSort(head);
        mergeSort(curr);
        merge(head, curr);
    }

    void merge(ListNode* &head, ListNode* &slow) { //这里的slow就是上面的curr,
        if(slow == nullptr) return ;   //一开始写没有把中点前改成nullptr所以用了slow
        
        ListNode *tmp = head, **cur = &head;
		/*其实这里可以
		ListNode header(-1);
		ListNode *cur = &header;
		那下面就没必要用(ListNode **)这么麻烦了
		*/
        while(tmp && slow) {
            if(tmp->val > slow->val) {
                *cur = slow;
                slow = slow->next;
            }
            else {
                *cur = tmp;
                tmp = tmp->next;
            }
            cur = &((*cur)->next);
        }
        if(tmp == nullptr) {
            *cur = slow;
        }
        else {
            *cur = tmp;
        }
    }
public:
    ListNode* sortList(ListNode* head) {
        if(head == nullptr) return head;

        mergeSort(head);
        return head;
    }
};

贴一个大佬写的递归归并排序,迭代版本看另一位大佬ivan_allen

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == NULL || head->next == NULL)
        {
            return head;
        }
        ListNode* pmid;
        ListNode* mid = head;
        ListNode* trail = head;
        while (trail && trail->next)
        {
            pmid = mid;
            mid = mid->next;
            trail = trail->next->next;
        }
        pmid->next = NULL;

        return twoWayMerge(sortList(head), sortList(mid));
    }

    ListNode* twoWayMerge(ListNode* l1, ListNode* l2) {
        ListNode header(-1);
        ListNode *p = &header;
        while (l1 && l2)
        {
            if (l1->val < l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }

        p->next = l1 == NULL ? l2 : l1;

        return header.next;
    }
};

作者:jiangtianyu007
链接:https://leetcode-cn.com/problems/sort-list/solution/kuai-man-zhi-zhen-er-lu-gui-bing-c-by-jiangtianyu0/
来源:力扣(LeetCode)

287. 寻找重复数

在这里插入图片描述

一. 修改数值

把nums[i] 作为索引,对对应索引的值乘 -1,这样当我们遇到某个数师负数时就可以知道我们已经修改过这个数了

//21.49
//22.03
class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        for(int i = 0; i < nums.size(); i++) {
            if(nums[abs(nums[i])-1] < 0) return abs(nums[i]);
            else nums[abs(nums[i])-1] *= -1;
        }
        return -1;
    }
};
二. 二分法查找法

类似于你有一个称,找出其中重量不同的小球。每次我们都取中值mid,然后看有多少个数大于mid,若超过一半则重复的数字必定在mid之后(mid+1),否则就在mid之前

class Solution {
    int helper(vector<int> & nums, int small, int large) {
        if(small == large) {
            return small;
        }

        int cntr, cntl, mid;
        cntl = cntr = 0;
        mid = (small+large)/2;
        for(int x : nums) {
            if(x < small || x > large) continue;

            if(x > mid) cntr++;
            else cntl++;
        }	//要注意再递归时,究竟时mid+1,还是mid
        return (cntl > cntr)? helper(nums, small, mid) : helper(nums, mid+1, large);
    }
public:
    int findDuplicate(vector<int>& nums) {
        return helper(nums, 1, nums.size()-1);
    }
};
三. 快慢指针

参考atbulbs在leetcode的答案,可以把索引看作指针,这样就会后多个位置指向同一个地方,相当于循环列表找相交点,可以在快慢指针第一次相遇时,从头多一个慢指针,两慢指针必定在列表中的循环处相遇(证明可以看atbulbs

var findDuplicate = function(nums) {
  let slowPointer = 0
  let fastPointer = 0
  while (true) {
    slowPointer = nums[slowPointer]
    fastPointer = nums[nums[fastPointer]]
    if (slowPointer == fastPointer) {
      let _slowPointer = 0
      while (nums[_slowPointer] !== nums[slowPointer]) {
        slowPointer = nums[slowPointer]
        _slowPointer = nums[_slowPointer]
      }
      return nums[_slowPointer]
    }
  }
};

作者:atbulbs
链接:https://leetcode-cn.com/problems/find-the-duplicate-number/solution/qian-duan-ling-hun-hua-shi-tu-jie-kuai-man-zhi-z-3/
来源:力扣(LeetCode)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值