167.两数之和II-输入有序数组

  1. 167.两数之和II-输入有序数组
    1. 167.1 题目
    2. 167.2 题解
      1. 双指针法
      2. 字典存储补数
    3. 167.3 代码
    4. 167.4 运行结果

167.两数之和II-输入有序数组


167.1 题目

给你一个下标从 1 开始的整数数组 numbers,该数组已按非递减顺序排列,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1]numbers[index2],则 1 <= index1 < index2 <= numbers.length

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1index2

你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9。因此 index1 = 1, index2 = 2。返回 [1, 2]

示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6。因此 index1 = 1, index2 = 3。返回 [1, 3]

示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1。因此 index1 = 1, index2 = 2。返回 [1, 2]

提示:

  • 2 <= numbers.length <= 3 * 10^4
  • -1000 <= numbers[i] <= 1000
  • numbers 按非递减顺序排列
  • -1000 <= target <= 1000
  • 仅存在一个有效答案

167.2 题解

双指针法

// 方法一:双指针法
// 头尾移动判断是否是目标值
static int[] TwoSum1(int[] numbers, int target)
{
    // 初始化左右指针
    int left = 0;
    int right = numbers.Length - 1;

    // 循环直到左指针大于右指针
    while (left < right)
    {
        // 计算当前左右指针指向的数字之和
        int sum = numbers[left] + numbers[right];
        // 如果和等于目标数,返回左右指针的下标
        if (sum == target)
        {
            return new int[] { left + 1, right + 1 };
        }
        // 如果和小于目标数,左指针右移一位
        else if (sum < target)
        {
            left++;
        }
        // 如果和大于目标数,右指针左移一位
        else
        {
            right--;
        }
    }

    // 没有找到符合条件的数对,返回[-1, -1]
    return new int[] { -1, -1 };
}

字典存储补数

// 方法二:字典存储补数
static int[] TwoSum2(int[] numbers, int target)
{
    // 创建哈希表,存储数字及其下标
    var dict = new Dictionary<int, int>();

    // 遍历数组
    for (int i = 0; i < numbers.Length; i++)
    {
        // 计算当前数字的补数
        int complement = target - numbers[i];
        // 如果补数在哈希表中存在,则返回其下标及当前数字的下标
        if (dict.ContainsKey(complement))
        {
            return new int[] { dict[complement] + 1, i + 1 };
        }

        // 将当前数字及其下标存入哈希表
        dict[numbers[i]] = i;
    }

    // 没有找到符合条件的数对,返回[-1, -1]
    return new int[] { -1, -1 };
}

167.3 代码

using System;

class Program
{
    static void Main()
    {
        #region 题目

        // 给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。
        // 如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。
        // 以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。
        // 你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
        // 你所设计的解决方案必须只使用常量级的额外空间。

        // 示例 1:
        // 输入:numbers = [2,7,11,15], target = 9
        // 输出:[1,2]
        // 解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

        // 示例 2:
        // 输入:numbers = [2,3,4], target = 6
        // 输出:[1,3]
        // 解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。

        // 示例 3:
        // 输入:numbers = [-1,0], target = -1
        // 输出:[1,2]
        // 解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

        // 提示:
        // 2 <= numbers.length <= 3 * 104
        // -1000 <= numbers[i] <= 1000
        // numbers 按 非递减顺序 排列
        // -1000 <= target <= 1000
        // 仅存在一个有效答案

        #endregion

        #region 测试

        // 示例 1
        int[] numbers1 = { 2, 7, 11, 15 };
        int target1 = 9;
        int[] result1_1 = TwoSum1(numbers1, target1);
        Console.WriteLine($"示例1 方法1 输出:[{result1_1[0]}, {result1_1[1]}]");
        int[] result1_2 = TwoSum2(numbers1, target1);
        Console.WriteLine($"示例1 方法2 输出:[{result1_2[0]}, {result1_2[1]}]");

        // 示例 2
        int[] numbers2 = { 2, 3, 4 };
        int target2 = 6;
        int[] result2_1 = TwoSum1(numbers2, target2);
        Console.WriteLine($"示例2 方法1 输出:[{result2_1[0]}, {result2_1[1]}]");
        int[] result2_2 = TwoSum2(numbers2, target2);
        Console.WriteLine($"示例2 方法2 输出:[{result2_2[0]}, {result2_2[1]}]");

        // 示例 3
        int[] numbers3 = { -1, 0 };
        int target3 = -1;
        int[] result3_1 = TwoSum1(numbers3, target3);
        Console.WriteLine($"示例3 方法1 输出:[{result3_1[0]}, {result3_1[1]}]");
        int[] result3_2 = TwoSum2(numbers3, target3);
        Console.WriteLine($"示例3 方法2 输出:[{result3_2[0]}, {result3_2[1]}]");

        #endregion
    }

    #region 答案

    // 方法一:双指针法
    // 头尾移动判断是否是目标值
    static int[] TwoSum1(int[] numbers, int target)
    {
        // 初始化左右指针
        int left = 0;
        int right = numbers.Length - 1;

        // 循环直到左指针大于右指针
        while (left < right)
        {
            // 计算当前左右指针指向的数字之和
            int sum = numbers[left] + numbers[right];
            // 如果和等于目标数,返回左右指针的下标
            if (sum == target)
            {
                return new int[] { left + 1, right + 1 };
            }
            // 如果和小于目标数,左指针右移一位
            else if (sum < target)
            {
                left++;
            }
            // 如果和大于目标数,右指针左移一位
            else
            {
                right--;
            }
        }

        // 没有找到符合条件的数对,返回[-1, -1]
        return new int[] { -1, -1 };
    }

    // 方法二:字典存储补数
    static int[] TwoSum2(int[] numbers, int target)
    {
        // 创建哈希表,存储数字及其下标
        var dict = new Dictionary<int, int>();

        // 遍历数组
        for (int i = 0; i < numbers.Length; i++)
        {
            // 计算当前数字的补数
            int complement = target - numbers[i];
            // 如果补数在哈希表中存在,则返回其下标及当前数字的下标
            if (dict.ContainsKey(complement))
            {
                return new int[] { dict[complement] + 1, i + 1 };
            }

            // 将当前数字及其下标存入哈希表
            dict[numbers[i]] = i;
        }

        // 没有找到符合条件的数对,返回[-1, -1]
        return new int[] { -1, -1 };
    }

    #endregion
}

167.4 运行结果

示例1 方法1 输出:[1, 2]
示例1 方法2 输出:[1, 2]
示例2 方法1 输出:[1, 3]
示例2 方法2 输出:[1, 3]
示例3 方法1 输出:[1, 2]
示例3 方法2 输出:[1, 2]


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏