Spider——排序

归并排序

排序一段序列分为排序前部分、后部分,再合并两个已经排序好的部分。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* merge(ListNode* head1,ListNode* head2)
    //将两个有序链表合并成为一个有序链表,返回链表的头指针
    {
        ListNode* dummyhead = new  ListNode(-1);
        ListNode* currents = dummyhead;
        while(head1 != NULL&&head2 != NULL)
        {
            if(head1->val <= head2->val)
            //每次取出head1节点与head2节点中的较小值
            //将其放插入合并的链表之中
            {
                currents->next = new  ListNode(head1->val);
                head1 = head1->next;
                currents = currents->next;
            }
            else
            {
                currents->next = new  ListNode(head2->val);
                head2 = head2->next;
                currents = currents->next;
            }
        }
        while(head1 != NULL)
        //如果其中还有节点的数值未被放完的时候
        //将剩余的节点插入到合并的链表之中
        {
            currents->next = new  ListNode(head1->val);
            currents = currents->next;
            head1 = head1->next;
        }
        while(head2 != NULL)
        {
            currents->next = new  ListNode(head2->val);
            currents = currents->next;
            head2 = head2->next;
        }
        currents->next = NULL;
        return  dummyhead->next;
        //返回合并链表的头指针
    }
    ListNode* cuts(ListNode* head,int  steps)
    {
        //切除链表,返回下一个链表的头指针
        ListNode* dummyhead = new  ListNode(-1);
        dummyhead->next = head;
        ListNode* currents = dummyhead;
        for(int  i=0;i<steps;i++)
        {
            if(currents->next == NULL)
            //放置链表的末尾有长度不够step的部分
            {
                break;
            }
            currents = currents->next;
        }
        ListNode* u = currents->next;
        //提前保存下一个链表的头指针
        currents->next = NULL;
        //将链表切断
        return  u;
        //返回下一个链表的头指针
    }
    ListNode* sortList(ListNode* head) {
        ListNode*  dummyhead = new  ListNode(-1);
        dummyhead->next = head;	//dummy指针确保头结点准确
        ListNode*  currents = head;
        int   total = 0;
        //确定链表长度
        while(currents)
        {
            total++;
            currents = currents->next;
        }
        ListNode* lefts;
        ListNode* rights;
        ListNode* nextleft;
        lefts = dummyhead->next;
        ListNode* tail = dummyhead;
        for(int  step = 1;step < total;step=step*2)
        {
            tail = dummyhead;
            //tail保存合并链表的头指针
            lefts = dummyhead->next;
            //两两合并,lefts指向第一个链表
            while(lefts != NULL)
            {
                rights = cuts(lefts,step);
                //切割后返回下一个链表的头指针
                nextleft = cuts(rights,step);
                tail->next = merge(lefts,rights);
                //将lefts链表与rights链表合并
                while(tail->next != NULL)
                {
                    tail = tail->next;
                }
                //尾指针后移,变为下一个节点的头指针
                lefts = nextleft;
                //lefts变为下一个合并链表的头指针
            }
        }
        return  dummyhead->next;
    }
};
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Soulution{
public:
	ListNode* sortList(ListNode *head)
	{
		if(head == NULL || head->next ==NULL)
			return head;
		ListNode *end = head;
		while(end && end->next){
			end = end->next;
		}
		return mergeSort(head,end);
	}

	//归并排序
	ListNode* mergeSort(Listnode *start, Listnode *end){
		//一个节点直接返回
		if(start == end)	return start;
		//两个节点则返回小到大
		if(start->next == end)
		{
			if(start->val >= end->val)
			{
				int temp = start->val;
				start->val = end->val;
				end->val = temp;
			}
			return start;
		}

		//快慢指针确定中点,二分法
		Listnode *slow = start,*fast = start;
		while(fast!=end){
			slow = slow->next;
			fast = fast->next;
			if(fast->next)	fast = fast->next;
		}
		//第一步,递归,排序右边
		ListNode * rightList = mergeSort(slow->next, end);
		slow->next = NULL; //将两个链表分开
		//第二步,排序左边
		ListNode * leftList = mergeSort(start, slow);
		
		//第三步,合并
		ListNode *pHead = NULL, *pEnd = NULL;//合并链表的头、尾
		if (rightList == NULL) {
			return leftList;
		}
		//初始化头结点、尾节点
		if (rightList->val > leftList->val) {
			pEnd = pHead = leftList;
			leftList = leftList->next;
		}
		else {
			pEnd = pHead = rightList;
			rightList = rightList->next;
		}
		//合并,每次将较小值放入新链表
		while(rightList && leftList)
		{
			if(rightList->val > leftList->val){
				pEnd ->next = leftList;
				pEnd = pEnd->next;
				leftList = leftList->next;
			}
			else{
				pEnd ->next = rightList;
				pEnd = pEnd->next;
				rightList = rightList->next;
			}
		}
		//添加剩余链表
		if(rightList->next==NULL)	pEnd->next = leftList;
		else 	pEnd->next = rightList;
		return pHead;
	}
};
/**
 * 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 == NULL || head->next == NULL) {
			return head;
		}
		return mergeSort(head);//去掉链表尾端的寻找
	}
	ListNode* mergeSort(ListNode* head) {
		if (head == NULL || head ->next == NULL) {//这段链表只有一个节点
			return head;
		}
        //快慢指针,定位链表中间
		ListNode *slowPtr = head, *fastPtr = head->next;
		while (fastPtr != NULL && fastPtr->next != NULL) {
			slowPtr = slowPtr->next;//慢指针走一步
			fastPtr = fastPtr->next;//快指针走两步
			if (fastPtr != NULL && fastPtr->next != NULL) {
				fastPtr = fastPtr->next;//快指针走两步
			}
		}
        
		//第一步  递归,排序右半
		ListNode * rightList = mergeSort(slowPtr->next);
		slowPtr->next = NULL;//将左右两部分切开
		//第二步 递归,排序左半
		ListNode * leftList = mergeSort(head);
        
		//第三步 合并
		ListNode *pHead = NULL, *pEnd = NULL;//合并链表的头、尾
		if (rightList == NULL) {
			return leftList;
		}
		//初始化头结点、尾节点
		if (rightList->val > leftList->val) {
			pEnd = pHead = leftList;
			leftList = leftList->next;
		}
		else {
			pEnd = pHead = rightList;
			rightList = rightList->next;
		}
		//合并,每次将较小值放入新链表
		while (rightList && leftList) {
			if (rightList->val > leftList->val) {
				pEnd->next = leftList;
				pEnd = pEnd->next;
				leftList = leftList->next;
			}
			else {
				pEnd->next = rightList;
				pEnd = pEnd->next;
				rightList = rightList->next;
			}
		}
		//可能某个链表有剩余
		if (rightList == NULL) {
			pEnd->next = leftList;
		}
		else {
			pEnd->next = rightList;
		}
		return pHead;
	}
};

快速排序

归并排序把数组分成两个数组分别排序再合并,而快速排序的方式是两个子数组都有序时整个数组也就有序了。
归并排序按数量将数组分成两半,快速排序按大小将数组分成两半。

时间复杂度 : 平均情况 O(N),最坏情况 O(N^2)
空间复杂度 : O(1)

class Solution
{
public:
    int findKthLargest(vector<int> &nums, int k)
    {
        int result = 0;
        int numsSize = int(nums.size());
        if (numsSize == 0 || k > numsSize)
        {
            return 0;
        }
        //寻找第kMIN小的数
        int kMin = numsSize - k + 1;
        result = select(nums, 0, numsSize - 1, kMin);
        return result;
    }

    int select(vector<int> &nums, int left, int right, int target)
    {
        if (left == right)
        {
            return nums[left];
        }
        int cut = partition(nums, left, right);
        //当前第currentResult小的元素
        int currentResult = cut - left + 1;
        if (target == currentResult)
        {
            return nums[cut];
        }
        else if (target < currentResult)
        {
            return select(nums, left, cut - 1, target);
        }
        else
        {
            //寻找接下来第target - currentResult小的数
            return select(nums, cut + 1, right, target - currentResult);
        }
        return 0;
    }

    int partition(vector<int> &nums, int left, int right)
    {
        int cut = nums[right];
        //i指向大堆的最左边的数,j指向下一个判断的数
        int i = left;
        for (int j = left; j < right; j++)
        {
            if (nums[j] <= cut)
            {
                exchange(nums[i], nums[j]);
                i++;
            }
        }
        exchange(nums[i], nums[right]);
        return i;
    }

    void exchange(int &a, int &b)
    {
        int tmpInt = a;
        a = b;
        b = tmpInt;
        return;
    }
};
class Solution
{
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
    {
       if(input.empty() || k<=0 || k > input.size()) return vector<int>(); //处理异常输入
      
        int left = 0, right = input.size()-1;
        int pivot_pos;
        while(left <= right)//类似二分查找法
        {
            pivot_pos = partition(input, left, right);//如果要求最大的第k个数,可以对partition函数进行改造
            if(pivot_pos < k-1)
                left = pivot_pos + 1;
            else if(pivot_pos > k-1)           
                right = pivot_pos - 1;
            else
                break;//此题要求的是返回最小的前k个数,如果仅返回最小的第k个数,直接在这里return a[pivot_pos]即可
                
        }
        vector<int> result(input.begin(), input.begin()+k); //构造结果向量
        return result;
    }
private:
    int partition(vector<int>& a, int left, int right)
    {
        //随机初始化枢轴 5ms
        //srand(time(nullptr)); //以当前时间为随机生成器的种子
        //int pivotpos = rand()%(right - left + 1) + left; //产生【left,right】之间的数
        //swap(a[pivotpos], a[left]); //将枢轴暂时放入起始位置
      
        int pivot = left; //枢轴位置 4ms
      
        while(left<right)
        {
            while(left < right && a[right] >= a[pivot]) right--; //找到本次扫描中第一个不满足枢轴规律的高位数
            while(left < right && a[left] <= a[pivot]) left++; //找到本次扫描中第一个不满足枢轴规律的低位数
            swap(a[left], a[right]); //交换以使满足枢轴规律
        }//最后结果是left和right均指向枢轴位置
        swap(a[left], a[pivot]); //将枢轴移动到位
        return left; //返回枢轴位置
    }
};

堆排序

利用小顶堆的特性(堆顶元素最小),先对前K个数组元素进行"原地"建小顶堆,建完小顶堆后,堆顶的元素最小,正好是这K个元素的第K大元素。
然后遍历剩下的元素 nums[k] ~ nums[len-1]

1、如果比堆顶元素小,跳过
2、如果比堆顶元素大,和堆顶元素交换后重新堆化
建堆 buildHeap 时间复杂度 O(K),遍历剩下元素并且堆化 时间复杂度(N-K)*O(logK),总体的时间复杂度 O(NlogK)

int findKthLargest(vector<int>& nums, int k)
{
	priority_queue<int,vector<int>,greater<int>> pq;	//维护一个 k 大小的小顶堆,堆顶就是第 k 个最大的数
	for(auto &n : nums){
		if(pq.size()>=k && pq.top()>=n)	continue;
		pq.push(n);
		if(pq.size()>k)	pq.pop();
	}
	return pq.top();
}

/*
2
*/
class Solution
{
public:
    int findKthLargest(vector<int> &nums, int k)
    {
        int numsSize = int(nums.size());
        if (numsSize == 0 || k > numsSize)    return 0;

        priority_queue<int, vector<int>, greater<int>> store;
        //堆中维持k个最大数
        for (int i = 0; i < numsSize; i++)
        {
            store.push(nums[i]);
            while (int(store.size()) > k) 	store.pop();
        }

        return store.top();
    }
};

//O(nlogn + klogn),O(1)
class Solution
{
public:
    int findKthLargest(vector<int>& nums, int k)
    {
        make_heap(nums.begin(),nums.end());//构建大顶堆,用nums存储,与下面区别就是节省了空间
        for(int i = 0; i<k-1;i++)
        {
            pop_heap(nums.begin(),nums.end()); //将堆顶元素移至末尾,重新调整使(begin~end-1)的元素满足堆规律
            nums.pop_back(); //移除末尾元素
        }
       
        return nums[0];
           
       
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值