前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Leetcode数组题目

Leetcode数组题目

作者头像
润森
发布2019-11-14 00:53:28
5960
发布2019-11-14 00:53:28
举报
文章被收录于专栏:毛利学Python毛利学Python

学习一时爽,一直学习一直爽

本文来自数据结构与算法之美 春节加餐

争哥:https://github.com/wangzheng0822/algo

数组题目

在这里插入图片描述

这不补下春节欠的债

Three Sum(求三数之和)

leetcode的第15题

https://leetcode-cn.com/problems/3sum/

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

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]

对于twosum就是遍历寻找另一个是不是在nums中

代码语言:javascript
复制
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        '''
        1、首先我们需要排序
        2、循环nums
        3、固定一个值,找另外二个值它们和等于 0
        4、如果三个数相加等于零则存储到相应的二维数组中
        :param nums:
        :return:
        '''
        result = []
        nums.sort()
        a = len(nums)
        # 固定最后值 找前面另外二个值它们和等于 0
        for i in range(a - 1):
            # 遍历前面的数组 如果它们和等于 0
            for j in range(i + 1, a):
                if -(nums[i] + nums[j]) in nums[j + 1:]:
                    array = [nums[i], nums[j], -(nums[i] + nums[j])]
                    if array not in result:
                        result.append(array)
        return result

但是这超时了,o(n2)时间复杂度不行

在这里插入图片描述 这是就有一种很特别的方法,

作者:jyd 链接:https://leetcode-cn.com/problems/3sum/solution/3sumpai-xu-shuang-zhi-zhen-yi-dong-by-jyd/ 来源:力扣(LeetCode)

解题思路:

  • 暴力法搜索为 O(N^3)O(N 3 )

时间复杂度,可通过双指针动态消去无效解来优化效率。

  • 双指针法铺垫:先将给定 nums 排序,复杂度为 O(NlogN)O(NlogN)。

双指针法思路:固定 3 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引 (k, len(nums))(k,len(nums)) 两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足 nums[k] + nums[i] + nums[j] == 0 的 i,j 组合:

当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即 33 个数字都大于 00 ,在此固定指针 k 之后不可能再找到结果了。

当 k > 0且nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。

i,j 分设在数组索引 (k, len(nums))(k,len(nums)) 两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j],并按照以下规则执行双指针移动:

  • 当s < 0时,i += 1并跳过所有重复的nums[i];
  • 当s > 0时,j -= 1并跳过所有重复的nums[j];
  • 当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。
代码语言:javascript
复制
class Solution:
    def threeSum(self, nums):
        # 如果列表长度小于3,则条件不成立,返回空列表
        if len(nums) < 3: return []
        n = len(nums)
        # 先排序
        nums.sort()
        list_nums = []

        # 从列表第一个数开始循环,和它右边选两个数相加,求和
        # 所以只能到倒数第三个数为止,因为倒数第二个数右边只有一个数
        for i in range(n - 2):

            # 因为列表已经按从小到大顺序排列了,如果左边数字大于0,则右边一定大于0
            # 则三数之和不可能为0
            if nums[i] > 0:
                break

            # 从第一个元素开始,如果它的左边元素和它相等,则跳过进行下一轮循环
            if i >= 1 and nums[i - 1] == nums[i]:
                continue

            # 分别从当前元素右边第一个元素和最右边元素开始,计算三个元素之和
            left, right = i + 1, n - 1
            # 如果左路元素没有和右路元素相交,则继续靠近
            while left < right:
                sums = nums[i] + nums[left] + nums[right]
                if sums == 0:
                    list_nums.append([nums[i], nums[left], nums[right]])
                    # 从左边开始移动到最后一个重复元素
                    while left < right and nums[left] == nums[left + 1]:
                        left += 1
                    # 从右边开始移动到最后一个重复元素
                    while left < right and nums[right] == nums[right - 1]:
                        right -= 1
                    # 跳过重复元素
                    left, right = left + 1, right - 1
                elif sums < 0:
                    left += 1
                else:
                    right -= 1

        return list_nums

将python改写成Java,思路一样

代码语言:javascript
复制
class Solution {
    public List<List<Integer>> threeSum(int[] num) {

        Arrays.sort(num);
        List<List<Integer>> res = new LinkedList<List<Integer>>();

        for (int i = 0; i < num.length-2; i++) {
            if (i == 0 || (i > 0 && num[i] != num[i-1])) {
                int left = i+1, right = num.length-1, sum = 0 - num[i];
                while (left < right) {
                    if (num[left] + num[right] == sum) {
                        res.add(Arrays.asList(num[i], num[left], num[right]));
                        while (left < right && num[left] == num[left+1]) left++;
                        while (left < right && num[right] == num[right-1]) right--;
                        left++; right--;
                    } else if (num[left] + num[right] < sum) left++;
                    else right--;
                }
            }
        }
        return res;
    }
}

leetcode 第169题

https://leetcode-cn.com/problems/majority-element/

给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在众数。

示例 1:

输入: [3,2,3] 输出: 3

示例 2:

输入: [2,2,1,1,1,2,2] 输出: 2

暴力算法

暴力算法遍历整个数组,然后用另一重循环统计每个数字出现的次数。将出现次数比其他数字加起来出现次数还多的元素返回。

代码语言:javascript
复制
class Solution:
    def majorityElement(self, nums):
        majority_count = len(nums)//2
        for num in nums:
            count = sum(1 for elem in nums if elem == num)
            if count > majority_count:
                return num

但是两次遍历时间复杂度O(n2),超时了

将nums排序,那些众数一定在中间

时间复杂度:O(nlgn)O(nlgn)

用 Python 和 Java 将数组排序开销都为 O(nlgn)O(nlgn) ,它占据了运行的主要时间。

空间复杂度:O(1)O(1)或者O(n)O(n)

代码语言:javascript
复制
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        return sorted(nums)[len(nums)//2]

但是py时间复杂度太大了

在这里插入图片描述

同样的方法用Java写

代码语言:javascript
复制
class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
}

速度快了几百倍

在这里插入图片描述

排序法是最好的方法

https://leetcode-cn.com/problems/first-missing-positive/

给定一个未排序的整数数组,找出其中没有出现的最小的正整数。

示例 1:

输入: [1,2,0] 输出: 3

示例 2:

输入: [3,4,-1,1] 输出: 2

示例 3:

输入: [7,8,9,11,12] 输出: 1

说明:

你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。

return的一定是0到len(nums)中的一个正整数
代码语言:javascript
复制
class Solution(object):
    def firstMissingPositive(self, nums):
        for i in range(1,len(nums)+2):
            if i not in nums:
                return i

改写成Java,思路一样

代码语言:javascript
复制
class Solution {
    public int firstMissingPositive(int[] nums) {
        int len = nums.length;
        int[] arr = new int[len+2];//定义一个新数组,最小的数字肯定就在新数组的下标中
        for (int item : nums) {
            if (item > 0 && item <= len) {
                //排除负数和大于输入数组长度的数,因为缺失的正数肯定小于数组的长度+1(这里需要仔细想清楚)
                arr[item] = 1;//新数组下标为1,则表示有这个数
            }
        }
        //这一步就简单了,遍历新数组,看看第一个没有的正整数是谁就行了
        for (int i = 1; i < len+2; i++) {
            if (0 == arr[i]) {
                return i;
            }
        }
        return len+1;//这一步为了应对空数组
    }
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小刘IT教程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Three Sum(求三数之和)
  • 暴力算法
    • return的一定是0到len(nums)中的一个正整数
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档