剑指offer-42、和为S的两个数字

题⽬描述

输⼊⼀个递增排序的数组和⼀个数字 S ,在数组中查找两个数,使得他们的和正好是 S ,如果有多对数字的和等于 S ,输出两个数的乘积最⼩的。

返回值描述:对应每个测试案例,输出两个数,⼩的先输出。

输⼊:1,2,4,7,11,15,15 返回值:4,11

思路及解答

暴⼒遍历

直接遍历每两个数,查看其和是否符合等于 sum ,再计算其乘积,是否⼩于之前的乘积,如果⼩于,则更新。

java 复制代码
public ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {
     ArrayList<Integer> results = new ArrayList<>();
     long mutip = 999999999;
     if (array != null && array.length > 2) {
         for (int i = 0; i < array.length - 1; i++) {
             for (int j = i + 1; j < array.length; j++) {
                 if (array[i] + array[j] == sum && array[i] * array[j] < mutip) {
                     results.clear();
                     results.add(array[i]);
                     results.add(array[j]);
                     mutip = array[i] * array[j];
                 } else if (array[i] + array[j] > sum) {
                 	break;
                 }
             }
         }
     }
     return results;
 }
  • 时间复杂度:O(n²),需要检查所有可能的数对组合
  • 空间复杂度:O(1),只使用常数级别额外空间

使⽤HashSet

针对每⼀个数字 a ,都查看 hashset 中是否存在 sum-a ,同时把该数字添加到 set 中。如果存在则计算其乘积,更新乘积最⼩值。

java 复制代码
public ArrayList<Integer> FindNumbersWithSum1(int[] array, int sum) {
     ArrayList<Integer> results = new ArrayList<>();
     long mutip = 999999999;
     HashSet<Integer> set = new HashSet<>();
     if (array != null && array.length > 2) {
         for (int i = 0; i < array.length; i++) {
             if (set.contains(sum - array[i]) && array[i]*(sum - array[i]) < mutip) {
                 results.clear();
                 results.add(sum-array[i]);
                 results.add(array[i]);
                 mutip = array[i] * (sum - array[i]);
             }
             set.add(array[i]);
         }
     }
     return results;
 }
  • 时间复杂度:O(n),只需遍历数组一次
  • 空间复杂度:O(n),需要HashSet存储元素

双指针法(最优)

利用数组有序特性:左右指针分别指向数组首尾,根据当前和动态调整指针位置

由于数组 nums\[\] 是有序的,也就是第⼀个数字是最⼩的,第⼆个数字是最⼤的,那么我们使⽤⼀个指针 i 指向数组第⼀个元素,⼀个指针 j 指向数组最后⼀个元素。

i 指针往右边移动, j 指针往左边移动,直到两者相撞(相等)。

如果 numsi+numsj == sum ,那么说明这个是可能存在的解,需要计算两者的乘积,如果⽐保存的乘积还⼩,则更新结果。同时左边指针 i 往右边移动⼀位,右边指针 j 往左边移动⼀位。

如果 numsi + numsj > sum ,则说明和太⼤了,⽐ sum 还要⼤,则右边的指针j需要左移⼀步,即是 j-- 。

如果 numsi + numsj < sum ,则说明和太⼩了,⽐ sum 还要⼩,则左边的指针i需要左移⼀步,即是 i++ 。

java 复制代码
public ArrayList<Integer> FindNumbersWithSum2(int[] array, int sum) {
     ArrayList<Integer> results = new ArrayList<>();
     long mutip = 999999999;
     if (array != null && array.length > 2) {
         int left = 0,right = array.length-1;
         while(left<right){
             if(array[left]+array[right]==sum){
                 if(array[left]*array[right]<mutip){
                     mutip = array[left]*array[right];
                     results.clear();
                     results.add(array[left]);
                     results.add(array[right]);
                 }
                 left++;
                 right--;
             }else if(array[left]+array[right]>sum){
                 right--;
             }else{
                 left++;
             }
         }
     }
     return results;
 }
  • 时间复杂度:O(n),最坏情况下左右指针共同遍历整个数组
  • 空间复杂度:O(1),只使用固定数量的指针变量
相关推荐
码智社14 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
萧瑟余晖15 小时前
JDK 26 新特性详解
java·开发语言
马优晨16 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
维天说18 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zane199419 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
噢,我明白了20 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品20 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘20 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
Java内核笔记20 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
糖果店的幽灵20 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph