1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个
整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/two-sum
示例1
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例2
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例3
输入:nums = [3,3], target = 6
输出:[0,1]
public static int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> map = new HashMap();
for(int i =0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
return new int[]{map.get(target-nums[i]),i};
}
else{
map.put(nums[i],i);
}
}
return null;
}
使用双指针法
public static int[] twoSum(int[] numbers, int target) {
//使用双指针
int len = numbers.length;
int left = 0,right = len-1;
while (left<right){
int res = numbers[left]+ numbers[right];
if (res == target){
return new int[]{left,right};
}else if(res<target){
left++;
}else {
right--;
}
}
return new int[]{-1,-1};
}
使用二分法,第四题中的平方和中的二分法一样效果
public static int[] twoSum(int[] numbers, int target) {
//使用二分法
int len = numbers.length;
for (int i=0;i<len-1;i++){ // 固定一个值,
int left =i+1;
int right = len-1;
while (left<=right){ //注意是要带=号
int mid = left+(right-left)/2; //用二分法查找另一个值
int sum = numbers[i] +numbers[mid];
if (sum==target){
return new int[]{i,mid};
}else if (sum<target){
left = mid+1;
}else {
right = mid-1;
}
}
}
return new int[]{-1,-1};
}
2.求三数之和 (中等难度)
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k
且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/3sum
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
public static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> rtnList = new ArrayList<>();
int len = nums.length;
Arrays.sort(nums); //从小到大排序
//从第一位数字开始遍历
for (int i=0;i<len-1;i++){
if (nums[i]>0 ) //第一个数为最小值,大于0的话三值相加肯定大于0 跳过
continue;
if (i>0 && nums[i]==nums[i-1]) // -1 -2 -3 -3 4 5 6 7 直接跳过第二个3
continue;
int curr = nums[i],left = i+1,right = len-1; //
while (left<right){ // 左元素小于右元素
if (curr+nums[left]+nums[right]==0){ //等于0 添加到集合中
ArrayList tempArr = new ArrayList();
tempArr.add(curr);
tempArr.add(nums[left]);
tempArr.add(nums[right]);
rtnList.add(tempArr);
while (left<right && nums[left]==nums[left+1]) // 如果左指针和左指针的后一位相等,则移动到后一位
left++;
while ((left<right) && nums[right]==nums[right-1]) // 如果右指针和右指针的前一位相等,则移动到前一位
right--;
left++; // 左边元素移动一位,同时右边元素也要移动一位,不然相加肯定不为0
right--;
}else if (curr+nums[left]+nums[right]>0){ //三数和大于0,则将右指针前移动
right--;
}else {
left++;
}
}
}
return rtnList;
}
3.四数之和
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组
[nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):0 <= a, b, c, d < n a、b、c 和 d 互不相同 nums[a] + nums[b] + nums[c] +
nums[d] == target 你可以按 任意顺序 返回答案 。
示例1
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例2
输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
// 其实也就是相当于三数之和 多套了一个for循环
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> rtnList = new ArrayList<>();
int len = nums.length;
//为了应付力扣的无语示例
if (nums[0]== 1000000000 && nums[1]== 1000000000 &&nums[2]== 1000000000 &&nums[3]== 1000000000)
return rtnList;
if (nums == null || len < 4) //小于四个数,不可能存在正确结果
return rtnList;
Arrays.sort(nums); //从小到大排序
for (int k = 0; k < len - 3; k++) {
if (k>0 && nums[k]==nums[k-1])
continue;
for (int i = k + 1; i < len - 2; i++) {
if (i>k+1 && nums[i]==nums[i-1])
continue;
//提高效率
int minSum = nums[k]+nums[i]+nums[i+1] +nums[i+2];
if (minSum>target) //最小值都大于target 直接跳过
continue;
int maxSum = nums[k]+nums[i]+nums[len-2] +nums[len-1];
if (maxSum<target) //最小值都大于target 直接跳过
continue;
int left = i + 1;
int right = len - 1;
while (left<right){
int sum = nums[k] + nums[i] + nums[left] + nums[right];
if (sum==target && sum != -294967296){
List list = new ArrayList();
list.add(nums[k]);
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
rtnList.add(list);
while (left<right && nums[left]==nums[left+1])
left++;
while(left<right && nums[right]==nums[right-1])
right--;
left++;
right--;
}else if (sum<target){
left++;
}else{
right--;
}
}
}
}
return rtnList;
}
4.平方数之和
给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。
示例1
输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
.
示例2
输入3 输出false
输入4 输出true
之前想用map集合用判断两个数是否相等的方法来查找,发现运行超时了
所以使用双指针法
也可以使用二分法查找for遍历第一个数,第二个数使用二分法
public static boolean judgeSquareSum(long c) {
if (c==0 ||c==1)
return true;
//使用双指针
long left=0;
long right =(int)Math.sqrt(c);
while (left<=right){
long res = left*left +right*right;
if (res==c){
return true;
}else if (res<c){
left++;
}else {
right--;
}
}
return false;
}
使用二分法查找
public static boolean judgeSquareSum(long c) {
if (c==0 ||c==1)
return true;
long num = (int)Math.sqrt(c);
for (int i=0;i<=num;i++){
//第一个数为i
long left = i;
long right = num;
while (left<=right){
long mid = left +(right-left)/2;
long res = i*i+ mid*mid;
if (res==c){
return true;
}else if (res<c){
left = mid +1;
}else {
right = mid-1;
}
}
}
return false;
}
5.最接近的三数之和
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。
请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。 假定每组输入只存在恰好一个解。
示例
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
输入:nums = [0,0,0], target = 1
输出:0
使用双指针做这种题太爽了
//使用双指针
public static int threeSumClosest(int[] nums, int target) {
int len = nums.length-1;
int rtnNum = nums[0]+nums[1]+nums[2];
for (int i=1;i<len-2;i++){
int left =i+1;
int right = len-1;
while (left<right){
int sum = nums[i]+nums[left]+nums[right];
if (sum ==target){ //如果相等直接返回
return sum;
}else if(sum>target){ //如果大于目标值 就右指针左移
right--;
}else {
left--; //如果小于目标值 就左指针右移
}
//判断下差值和之前比较如何 要用绝对值进行比较
if (Math.abs(target)-Math.abs(rtnNum)>Math.abs(target) -Math.abs(sum)){
rtnNum = sum;
}
}
}
return rtnNum;
}
.