目录
哈希
两数之和
题目
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
数据范围:2≤𝑙𝑒𝑛(𝑛𝑢𝑚𝑏𝑒𝑟𝑠)≤105,−10≤𝑛𝑢𝑚𝑏𝑒𝑟𝑠𝑖≤109,0≤𝑡𝑎𝑟𝑔𝑒𝑡≤109
要求:空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛𝑙𝑜𝑔𝑛)
示例1
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]
示例2
输入:[20,70,110,150],90
返回值:[1,2]
说明:20+70=90
分析
记住哈希表可以快速查找某个元素是否存在。
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
public int[] twoSum (int[] numbers, int target) {
// write code here
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<numbers.length;i++){
int x=numbers[i];
if(map.containsKey(target-x)){
return new int[]{map.get(target-x)+1,i+1};
}
map.put(x,i);
}
return new int[0];
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param numbers int整型一维数组
# @param target int整型
# @return int整型一维数组
#
class Solution:
def twoSum(self , numbers: List[int], target: int) -> List[int]:
# write code here
index={}
for j,x in enumerate(numbers):
if target-x in index:
return [index[target-x]+1,j+1]
index[x]=j
数组中出现次数超过一半的数字
题目
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:𝑛≤50000,数组中元素的值 0≤𝑣𝑎𝑙≤10000
要求:空间复杂度:𝑂(1),时间复杂度 𝑂(𝑛)
输入描述:
保证数组输入非空,且保证有解
示例1
输入:[1,2,3,2,2,2,5,4,2]
返回值:2
示例2
输入:[3,3,3,3,2,2,2]
返回值:3
示例3
输入:[1]
返回值:1
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型一维数组
* @return int整型
*/
public int MoreThanHalfNum_Solution (int[] numbers) {
// write code here
Map<Integer,Integer> map=new HashMap<>();
for(int i:numbers){
if(map.containsKey(i)){
map.replace(i,map.get(i)+1);
}else{
map.put(i,1);
}
}
for(int i:map.keySet()){
if(map.get(i)>numbers.length/2){
return i;
}
}
return -1;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param numbers int整型一维数组
# @return int整型
#
class Solution:
def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
# write code here
index={}
for num in numbers:
if num in index:
index[num]+=1
else:
index[num]=1
for key in index:
if index[key]>len(numbers)/2:
return key
return -1
数组中只出现一次的两个数字
题目
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
数据范围:数组长度 2≤𝑛≤1000,数组中每个数的大小 0<𝑣𝑎𝑙≤1000000
要求:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛)
提示:输出时按非降序排列。
示例1
输入:[1,4,1,6]
返回值:[4,6]
说明:返回的结果中较小的数排在前面
示例2
输入:[1,2,3,3,2,9]
返回值:[1,9]
分析
首先要知道 a^b^a=a^a^b=b,如果数组中除了某一个数字,其他数字都出现了两次,找出该数字。思路就是遍历数组,对每一个数字都求异或,最后得到的值就是要找的数字。
本题是要找两个数字a和b,那我们把该数组分成两个数组,其中a和一部分出现两次的数字在一块儿,b和另一部分出现两次的数字在一块儿,然后再分别对这两个数组求异或,就可以找到这两个数字了。
怎么把a和b区分开来?
可以利用二进制来区分。先对整个数组求异或得到c,根据上面的知识,可以知道c其实就是a^b=c。那么对于c,假如c二进制的第一位是1,其实就代表a二进制的第一位是1(或0),b二进制的第一位是0(或1),总而言之如果第一位的c等于1,那么a和b在第一位肯定不相等。
所以我们就可以想到利用二进制的第一位(有可能是第二位,第三位 。。。因为上面是假设的c第一位是1)为1来区分两个数组,第一位为1的是数组一,第一位为0的是数组二。这样就相当于把a和b给区分开来了。
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型一维数组
*/
public int[] FindNumsAppearOnce (int[] nums) {
// write code here
if(nums==null || nums.length==0){
return new int[0];
}
int res=0;
for(int x:nums){
res=res^x;
}
// 第二步:找到第一个为 1 的二进制位 index
int index = 0;
while ((res & 1) == 0) {
res = res >> 1;
index++;
}
// 第三步:分组异或
int a = 0, b = 0;
for (int num : nums) {
if (helper(num, index)) {
a ^= num;
} else {
b ^= num;
}
}
return a < b ? new int[]{a, b} : new int[]{b, a};
}
// 辅助函数:判断数字 num 第 index 位是否为 1
private boolean helper(int num, int index) {
num = num >> index;
return (num & 1) != 0;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型一维数组
#
class Solution:
def FindNumsAppearOnce(self , nums: List[int]) -> List[int]:
# write code here
if not nums:
return []
# 第一步:整个数组异或,得到 a ^ b
res = 0
for x in nums:
res ^= x
# 第二步:找到第一个为 1 的二进制位 index
index = 0
while (res & 1) == 0:
res = res >> 1
index += 1
# 第三步:根据第 index 位分组异或
a, b = 0, 0
for num in nums:
if self.helper(num, index):
a ^= num
else:
b ^= num
# 按升序返回
return [a, b] if a < b else [b, a]
# 辅助函数:判断数字 num 第 index 位是否为 1
def helper(self,num, index):
num = num >> index
return (num & 1) != 0
缺失的第一个正整数
题目
给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数
进阶: 空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛)
数据范围:
−231≤𝑛𝑢𝑚𝑠[𝑖]≤231−1
0≤𝑙𝑒𝑛(𝑛𝑢𝑚𝑠)≤5∗105
示例1
输入:[1,0,2]
返回值:3
示例2
输入:[-2,3,4,1,5]
返回值:2
示例3
输入:[4,5,6,8,9]
返回值:1
分析
想象有一间教室,座位从左到右编号为 1 到 n。
有 n 个学生坐在教室的座位上,把 nums[i] 当作坐在第 i 个座位上的学生的学号。我们要做的事情,就是让学号在 1 到 n 中的学生,都坐到编号与自己学号相同的座位上(学号与座位编号匹配)。学号不在 [1,n] 中的学生可以忽略。
学生们交换座位后,从左往右看,第一个学号与座位编号不匹配的学生,其座位编号就是答案。
特别地,如果所有学生都坐在正确的座位上,那么答案是 n+1。
假设数组的下标是从 1 开始的。
假设 nums=[2,3,1]。
从 nums[1] 开始。这个座位上的学生,学号是 2,他应当坐在 nums[2] 上,所以他和 nums[2] 交换。交换后 nums=[3,2,1]。
仍然看 nums[1],这个座位上的学生,学号是 3,他应当坐在 nums[3] 上,所以他和 nums[3] 交换。交换后 nums=[1,2,3]。
仍然看 nums[1],这个座位上的学生,学号是 1,他坐在正确的座位上。
向后遍历,nums[2]=2,他坐在正确的座位上。
向后遍历,nums[3]=3,他坐在正确的座位上。
换座位过程结束。
再次遍历 nums,发现 nums[i]=i 都满足,说明数组中 1,2,3 都有,所以缺失的第一个正数是 4。
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public int minNumberDisappeared (int[] nums) {
// write code here
int n=nums.length;
for(int i=0;i<nums.length;i++){
while(1<=nums[i] && nums[i]<=n && nums[nums[i]-1]!=nums[i]){
int j=nums[i]-1; // 减一是因为数组下标从 0 开始
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
for (int i = 0; i < n; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return n+1;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param nums int整型一维数组
# @return int整型
#
class Solution:
def minNumberDisappeared(self , nums: List[int]) -> int:
# write code here
n=len(nums)
for i in range(n):
while nums[i]>=1 and nums[i]<=n and nums[nums[i]-1]!=nums[i]:
j=nums[i]-1
temp=nums[i]
nums[i]=nums[j]
nums[j]=temp
for i in range(n):
if nums[i]!=i+1:
return i+1
return n+1
三数之和
题目
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
数据范围:0≤𝑛≤1000,数组中各个元素值满足 ∣𝑣𝑎𝑙∣≤100
空间复杂度:𝑂(𝑛2),时间复杂度 𝑂(𝑛2)
注意:
- 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
- 解集中不能包含重复的三元组。
例如,给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, -10, 20),(-10, 0, 10)
示例1
输入:[0]
返回值:[]
示例2
输入:[-2,0,1,1,2]
返回值:[[-2,0,2],[-2,1,1]]
示例3
输入:[-10,0,10,20,-10,-40]
返回值:[[-10,-10,20],[-10,0,10]]
分析
这道题重点是去重
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param num int整型一维数组
* @return int整型ArrayList<ArrayList<>>
*/
public ArrayList<ArrayList<Integer>> threeSum (int[] num) {
// write code here
ArrayList<ArrayList<Integer>> result=new ArrayList<>();
Arrays.sort(num);
for(int i=0;i<num.length;i++){
if(i>0 && num[i]==num[i-1]){
continue;
}
int left=i+1;
int right=num.length-1;
while(left<right){
int sum=num[i]+num[left]+num[right];
if(sum>0){
right-=1;
}else if(sum<0){
left+=1;
}else{
result.add(new ArrayList<>(Arrays.asList(num[i],num[left],num[right])));
while (right > left && num[right] == num[right - 1]) right--;
while (right > left && num[left] == num[left + 1]) left++;
left++;
right--;
}
}
}
return result;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param num int整型一维数组
# @return int整型二维数组
#
class Solution:
def threeSum(self , num: List[int]) -> List[List[int]]:
# write code here
num.sort()
result=[]
for i in range(len(num)):
if i>0 and num[i]==num[i-1]:
continue
left=i+1
right=len(num)-1
while left<right:
sum=num[i]+num[left]+num[right]
if sum>0:
right-=1
elif sum<0:
left+=1
else:
result.append([num[i],num[left],num[right]])
while left<right and num[right]==num[right-1]:
right-=1
while left<right and num[left]==num[left+1]:
left+=1
right-=1
left+=1
return result