学习一时爽,一直学习一直爽
本文来自数据结构与算法之美 春节加餐
争哥:https://github.com/wangzheng0822/algo
数组题目
在这里插入图片描述
这不补下春节欠的债
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中
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)
解题思路:
时间复杂度,可通过双指针动态消去无效解来优化效率。
双指针法思路:固定 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],并按照以下规则执行双指针移动:
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,思路一样
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
暴力算法遍历整个数组,然后用另一重循环统计每个数字出现的次数。将出现次数比其他数字加起来出现次数还多的元素返回。
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)
class Solution:
def majorityElement(self, nums: List[int]) -> int:
return sorted(nums)[len(nums)//2]
但是py时间复杂度太大了
在这里插入图片描述
同样的方法用Java写
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),并且只能使用常数级别的空间。
class Solution(object):
def firstMissingPositive(self, nums):
for i in range(1,len(nums)+2):
if i not in nums:
return i
改写成Java,思路一样
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;//这一步为了应对空数组
}
}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有