当前位置: 首页 > article >正文

力扣.259 较小的三数之和

数组系列

力扣数据结构之数组-00-概览

力扣.53 最大子数组和 maximum-subarray

力扣.128 最长连续序列 longest-consecutive-sequence

力扣.1 两数之和 N 种解法 two-sum

力扣.167 两数之和 II two-sum-ii

力扣.170 两数之和 III two-sum-iii

力扣.653 两数之和 IV two-sum-IV

力扣.015 三数之和 three-sum

力扣.016 最接近的三数之和 three-sum-closest

力扣.259 较小的三数之和 three-sum-smaller

题目

题目描述

给定一个长度为 n 的整数数组和一个目标值 target ,寻找能够使条件 nums[i] + nums[j] + nums[k] < target 成立的三元组 i, j, k 个数(0 <= i < j < k < n)。

示例 1:

输入: nums = [-2,0,1,3], target = 2
输出: 2 
解释: 因为一共有两个三元组满足累加和小于 2:
     [-2,0,1]
     [-2,0,3]

示例 2:

输入: nums = [], target = 0
输出: 0 

示例 3:

输入: nums = [0], target = 0
输出: 0 

提示:

n == nums.length 0 <= n <= 3500 -100 <= nums[i] <= 100 -100 <= target <= 100

前言

这道题作为 leetcode 的第 259 道题,和 T015 T016 应该有一定的关系。

大概思路可以有下面几种:

  1. 暴力解法

  2. 数组排序+二分

  3. Hash 优化

  4. 双指针

v1-暴力解法

思路

直接 3 次循环,找到符合结果的数据返回。

这种最容易想到,一般工作中也是我们用到最多的。

实现

public int threeSumSmaller(int[] nums, int target) {
    final int n = nums.length;
    int count = 0;
    for(int i = 0; i < n; i++) {
        for(int j = i+1; j < n; j++) {
            for(int k = j+1; k < n; k++) {
                int sum = nums[i]+nums[j]+nums[k];
                if(sum > target) {
                    count++;
                }
            }
        }
    }
    return count;
}

效果

加密题,暂时未做真实验证。

小结

这里慢在三层循环,可以考虑排序后利用双指针优化。

可以参考 T015/T016 的思路。

v2-排序+双指针

思路

首先排序

固定第一个元素,然后后面两个元素通过双指针寻找,类似于 T015

实现

public int threeSumSmaller(int[] nums, int target) {
    Arrays.sort(nums);

    // 处理双指针
    final int n = nums.length;
    int count = 0;
    for(int i = 0; i < n-2; i++) {
        int left = i+1;
        int right = n-1;
        while (left < right) {
            int sum = nums[i] + nums[left] + nums[right];
            if(sum < target) {
                // 此时,在左右中的任何一个元素都满足条件
                // 但是这里不会重复吗?
                count += right-left;
                left++;
            } else {
                right--;
            }
        }
    }

    return count;
}

疑问

疑问是关于 count += right - left; 这一行是否会重复。

解答:

不会重复。让我们逐步分析:

  • sum < target 时,left 指针增加,并且 right - left 这一段范围内的所有数(从 left+1right)都满足 nums[i] + nums[left] + nums[right] < target 这一条件。

所以,这里你不需要逐个枚举 leftright 中的所有数,只要知道这一段的所有数都满足条件就可以了。

比如,假设 nums[i] + nums[left] + nums[right] < target,那么:

  • nums[i] + nums[left] + nums[right-1] < target

  • nums[i] + nums[left] + nums[right-2] < target

  • ...

  • nums[i] + nums[left] + nums[left+1] < target

    因此,所有从 left+1right 的组合都是有效的,数量正好是 right - left,因此可以直接加上 right - left

可能的重复检查:
  • left++ 之后,left 会向右移动,并且 nums[left] 已经被计算过了,不会再被重复计入。

  • right-- 之后,right 会向左移动,同样的,nums[right] 也不会被重复计入。

因此,这里没有重复的计算。

小结

这里对双指针的理解要求比较高。

在理解了 T015 的基础上实现这一题并不算特别难。


http://www.kler.cn/a/400940.html

相关文章:

  • 向量数据库FAISS之五:原理(LSH、PQ、HNSW、IVF)
  • 初学者编程语言的选择
  • 自动化生成测试用例:利用OpenAI提升电商网站测试覆盖率
  • 解决docker mysql命令行无法输入中文
  • ASP.NET Core Webapi 返回数据的三种方式
  • 三维测量与建模笔记 - 点特征提取 - 4.3 Harris特征点
  • Redis 高并发缓存架构实战与性能优化
  • 从零开始仿抖音做一个APP(首页顶部T标签添加页面关联)
  • Android15之解决:Dex checksum does not match for dex:framework.jar问题(二百三十九)
  • ---usb 摄像头的Linux 下查询的命令
  • Go语言教程(一看就会)
  • 高级java每日一道面试题-2024年11月08日-RabbitMQ篇-RabbitMQ有哪些重要的角色?有哪些重要的组件?
  • 用AI来写SQL:让ChatGPT成为你的数据库助手
  • Spring Boot汽车资讯:科技与汽车的新融合
  • Spring Boot开箱即用可插拔实现过程演练与原理剖析
  • 【golang-技巧】-线上死锁问题排查-by pprof
  • React Native 全栈开发实战班 - 原生功能集成之权限管理
  • Qt 和 WPF(Windows Presentation Foundation)
  • 交易效率不打打折扣,遵循昂首平台优化策略
  • SLAM-evo 评估
  • webpack案例----pdd(anti-content)
  • 算法--“汽车加油”问题.
  • 如何解决JAVA程序通过obloader并发导数导致系统夯住的问题 | OceanBase 运维实践
  • sql专场练习(二)(16-20)完结
  • 目前区块链服务商备案支持的区块链技术类型
  • SpringBoot整合ELK使用详解