215.第k大元素25.分组反转链表15.三数之和21.合并两个有序链表(快排,堆排)

215.数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

  1. 快排。唯一要注意的地方就是退出函数的条件,当待排序数组只有一个元素(k=1),那么结果就是它。这里没有考虑剪枝,即当前这一轮排序后确定的位置如果正好是第k个大的数字,则可以直接退出返回,不必进行到只剩一个元素待排序数组的情况。
public int quicksort(int[] nums,int low,int high,int k)
    {
        //if(low>=high)
        //return ;
        if(low==high)
        return nums[high];
        int base=nums[low];
        int left=low,right=high;
        while(low<high)
        {
            while(low<high&&nums[high]>=base)
            high--;
            while(low<high&&nums[low]<=base)
            low++;
            if(low<high)
            {
                int temp=nums[high];
                nums[high]=nums[low];
                nums[low]=temp;
            }
        }//这里循环出来必定有low=high
        nums[left]=nums[high];
        nums[high]=base;
        //quicksort(nums,left,low-1);
        //quicksort(nums,high+1,right);
        if(right-high>=k)
        return quicksort(nums,high+1,right,k);
        else
        return quicksort(nums,left,high,k-(right-high));

    }
  1. 堆排序。整个堆排序巧妙的地方在于,大根堆的排序和每轮排序后结果(堆顶元素)都是保存在一个数组中。排序过程中堆空间变小,排序后的有序数组空间变大。因此自顶向下调整堆时,maxHeapify()的形参中要包含当前所要调整的堆的大小。其它要考虑清楚的就以下几点:
  • 顺序存储的二叉树左孩子和右孩子表示方式。
  • 堆调整时左孩子或者右孩子越界的限制条件。
  • 初始堆时从哪个位置开始调整。
    public int findKthLargest(int[] nums, int k) {
       buildMaxHeap(nums);
       int heapsize=nums.length;
       for(int i=0;i<k;i++)
       {
           swap(nums,0,nums.length-1-i);
           heapsize--;    //排序完一轮堆大小减1
           maxHeapif(nums,0,heapsize);
       }
       return nums[nums.length-k];     
    }
    public void buildMaxHeap(int[] nums) //初始堆
    {
        for(int i=(nums.length-1)/2;i>=0;i--)
            maxHeapif(nums,i,nums.length);
    }
    public void maxHeapif(int[] nums,int target,int heapsize)
    {
        int left=target*2+1,right=target*2+2,max=target;
        if(left<heapsize&&nums[max]<nums[left])
        max=left;
        if(right<heapsize&&nums[max]<nums[right])
        max=right;
        if(max==target) //满足堆定义返回
        return;
        swap(nums,target,max);
        maxHeapif(nums,max,heapsize);
    }

25.K个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

  1. 第一步要先遍历一轮链表,找到最后一个不够k个节点的组的首节点,做法是设置一个计数器,每加到k就换一次首节点。这里注意遍历时候每次只能后移一个结点,跨两个在某些情况下容易出错。
  2. 第二步进行分组的反转,原理跟先前链表原地逆置差不多,只不过多了个分组,要把逆置后的组的尾节点设置为新的头结点(头插法),并且链接下一个组的头结点。phead是每个组的头结点,pend是每个组的尾结点。
public ListNode reverseKGroup(ListNode head, int k) {
            ListNode p=head,rhead=null;
            int group=1;
            while(p!=null)
            {
                if(group==k)
                {
                    rhead=p.next;
                    group=1;
                    p=p.next;
                    continue;
                }
                group++;
                p=p.next;
            }
            ListNode phead=new ListNode(0,head),res=phead;
            p=head;
            group=0;
            ListNode pnext,pend=null;
            while(p!=rhead)
            {
                if(group==k)
                {
                    phead=pend;
                    pend.next=p;
                    group=0;
                }
                pnext=p.next;

                if(group==0)
                {p.next=null;
                 pend=p;
                }
                else
                p.next=phead.next;

                phead.next=p;
                p=pnext;
                group++;
            }
            pend.next=rhead;
            return res.next;
    }

15.三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

  1. 先对数组进行排序,然后使用双指针法,这点非常难想到。因为只有数组有序才能使用双指针法,而双指针法是固定遍历子数组左端点nums[i],low=i,high=nums.length-1,通过移动low和high来使三数之和逼近零。只有当low和high相碰时才退出这一轮循环。
  2. 另一个难点在于去重。需要注意的是如果只去重不剪枝很可能会超时,因此把结果加入数组后,再通过while(nums[low]==nums[low-1])剪枝,这样子就不会超时了。
  3. new ArrayList<>(Arrays.asList(a,b,c)):通过反射将数组转换成集合 Arrays.sort(nums):排序
public List<List<Integer>> threeSum(int[] nums) {
          Arrays.sort(nums);
          List<List<Integer>> res=new ArrayList<>();          
          for(int i=0;i<nums.length-2;i++)
           {
               if(nums[i]>0)
               return res;
               if(i>0&&nums[i]==nums[i-1])
               continue;
               int low=i+1,high=nums.length-1;
               while(low<high)
               {
                while(low<high&&nums[i]+nums[low]+nums[high]<0)
                low++;
                while(low<high&&nums[i]+nums[low]+nums[high]>0)
                high--;
                if(low<high&&nums[i]+nums[low]+nums[high]==0)
                {
               res.add(new ArrayList<>(Arrays.asList(nums[i],nums[low],nums[high])));
                    while (low<high && nums[high] == nums[high- 1]) high--;
                    while (low<high && nums[low] == nums[low+1]) low++;
                    high--;
                    low++;
                }
               }
           } 
           return res;}

21.合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

  1. 找出首元素更小的一个链表,让另一个链表插入其中。被插入的小链表要考虑前驱(可以new一个头结点更好处理),插入的大链表要考虑后继。


今日总结

刷题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值