Day5 LeetCode 23 26 33

Day5 LeetCode 23 26 33

目录

Day5 LeetCode 23 26 33

1. 合并K个升序链表(LeetCode 23 题)

1.1题目

1.2思路

1.3代码

2.删除排序数组中的重复项(LeetCode 26 题)

2.1 题目

2.2 思路

2.3 代码

 3.搜索旋转排序数组(LeetCode 33 题)

3.1 题目

3.2 思路

3.3 代码

4 小结


1. 合并K个升序链表(LeetCode 23 题)

1.1题目

 

1.2思路

第一次做困难题,一次通过测试哈哈哈哈。

说一下本题思路,首先就是有很多有序的链表,你需要在短时间内把这些链表整理到一个链表里,同时保证新链表有序。

我们可以把这个问题化简一些。如果这个数组里只有两个链表,怎么办?

这就是把21题合并两个链表的问题扩展了。

首先合并两个链表的方法我再重新讲一下,你需要准备一个新链表来存储你新链表,那么可以依次对两个链表中的值进行比较。小的数放入新链表,大的数等待下次计较。如果其中一个链表遍历结束,即可把剩余的链表并入。

然后我们看看如何把许多个这样的链表合并起来,我采用的方法是分治的思想,然后通过递归来实现。

首先构建我们的返回链表,对长度等于1的链表直接返回原数据。如果长度大于2,就对前半部分进行单独合并,后半部分单独合并。这样相当于整体数据递归的分出两部分进行合并,然后逐级整合。时间复杂度为nlogn。通过mergeKLists逐级拆分,然后通过mergeTwoLists逐级合并。

1.3代码

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
            ListNode returnans = new ListNode(0);
            ListNode keypoint = returnans;
            if (lists.length==1) return lists[0];
            else if (lists.length>=2)
            return mergeTwoLists(
                    mergeKLists(Arrays.copyOfRange(lists,0,lists.length/2)),
                    mergeKLists(Arrays.copyOfRange(lists,lists.length/2,lists.length))
                );
            return keypoint.next;
        }
    public  ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode returnans = new ListNode(0);
        ListNode keypoint = returnans;
        while (l1!=null&&l2!=null){
            if (l1.val<l2.val){
                keypoint.next = l1;
                l1 = l1.next;
            }else {
                keypoint.next = l2;
                l2 = l2.next;
            }
            keypoint = keypoint.next;
        }
        keypoint.next = (l1!=null)?l1:l2;
        return returnans.next;
    }
}

2.删除排序数组中的重复项(LeetCode 26 题)

2.1 题目

 

2.2 思路

看到这个题的时候,我比较大意没有认真读题,想着简单题随便写。但是测试没过就认真读了读。

我们需要做两件事,一个是找出有多少个不重复元素,另一个就是原来数组的前N项必须为不重复元素的数。

我采用了双指针的解法,首先判断输入的列表是否为空。其次简历指针ans和指针i,i是保证我们可以遍历完数组,ans做返回长度的同时也实现了对nums的更新。

首先ans设为0,因为我们从头开始遍历,然后如果后面与【0】的数据不同表示出现了新的不重复项。(题目给定递增)

采用循环的方式,对每个数据进行遍历,如果数据和ans的数据不同,ans增加1,即达到对前N个数据的更新,也能让返回不重复个数的数量得到保证。

时间复杂度n 空间复杂度1。

2.3 代码

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums==null) return 0;
        int ans = 0;
        for(int i = 0; i<nums.length;i++){
            if(nums[i]!=nums[ans]){
                nums[++ans]= nums[i];
            }
        }
        return ans+1;
    }
}

 

 3.搜索旋转排序数组(LeetCode 33 题)

3.1 题目

 

3.2 思路

第一次看到这个题还挺懵逼的,然后看了题解,然后用二分的方法还是没解出来。再看了一次题解发现题目还是出的很不错。需要对题目有一定的理解才能很好地解答。

首先从暴力解法开始,就是遍历一遍,然后直接找到我们的答案,我想这样解答虽然没问题但是还有更巧妙的方法在等我们。

递归二分查找的方法如下,首先我们对原函数重写,searchp(int[] nums,int target ,int start,int end);

加入双指针进行判断。然后写跳出递归的条件,

if(end-start<=1){
                if (nums[start]==target) return start;
                else if (nums[end]==target) return end;
                else return -1;

}

这里我解释一下为什么这样写,首先start,end是对指针的记录,因为本题需要返回的是一个下标。有两个指针方便我们后面对二分方法递归的调用,所以重写了原方法。同时初始化了start,end指针的值0和length-1。接下来就是如果数组长度小于等于1,就直接判断,也就是我们跳出递归的条件。

说一下递归主体部分,如果这个题不是旋转的序列,大家可以简单的递归二分查找的方法很方便的找到。但是我们这里的序列进行了旋转。这个操作可能就会难住大家。讲一下怎么对转的序列进行解析。

如果序列旋转,在start,(start+end)/2,end 这三个点我们可以划分成两个区域。

拿这两个区域举一些例子。

0,1,3,4  target = 1, start ->0  (start+end)/2 ->1  end->4 

3,4,0,1  target = 3, start ->3  (start+end)/2 ->4  end->1 

0,1,3,4  target = 1, start ->0  (start+end)/2 ->1  end->4 

3,4,5,0,1  target = 3, start ->3  (start+end)/2 ->5  end->1 

 

如果start<(start+end/2) ,start <=target<=(start+end)/2,说明target在有序的区域。 另一边可能是无序。

如果start>(start+end/2) ,(start+end)/2<=target<=end,说明target在有序的区域。 另一边可能是无序。

这样子就可以把代码分成四块 然后进行分别递归查找,减少一般的查找时间和空间。

3.3 代码

class Solution {
    public int search(int[] nums, int target) {
            int start = 0;
            int end = nums.length-1;
            return searchp(nums,target,start,end);
        }
        public int searchp(int[] nums,int target ,int start,int end){
            if(end-start<=1){
                if (nums[start]==target) return start;
                else if (nums[end]==target) return end;
                else return -1;
            }else {
                if (nums[start]>nums[(start+end)/2]){
                    if (nums[(start+end)/2]<=target&&nums[end]>=target){
                        return searchp(nums,target,(start+end)/2,end);
                    }else {
                        return searchp(nums,target,start,(start+end)/2);
                    }
                }else {
                    if (nums[(start+end)/2]>=target&&nums[start]<=target){
                        return searchp(nums,target,start,(start+end)/2);
                    }else {
                        return searchp(nums,target,(start+end)/2,end);
                    }
                }
            }
        }
}

4 小结

今天的题目比较复杂,也是完成最晚的一次。但是在之前学习的铺垫下不觉得有多困难,同时最近进步飞快,代码的逻辑性和条理性都得到了很大的提升。继续加油!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值