LeetCode 第一题: 两数之和

文章目录

  • 第一题: 两数之和
  • 题目描述
    • 示例
  • 解题思路
  • Go语言实现 - 一遍哈希表法
    • C++实现
    • 算法分析
  • 排序和双指针法
    • Go语言实现 - 排序和双指针法
    • C++
    • 算法分析
  • 暴力法
    • Go语言实现 - 暴力法
    • C++
    • 算法分析
  • 二分搜索法
    • Go语言实现 - 二分搜索法
    • C++
    • 算法分析

第一题: 两数之和

题目描述

给定一个整数数组 nums​ 和一个目标值 target​,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组索引。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解题思路

  1. 暴力法:双重循环遍历数组中的每个数,寻找是否存在一个数与它相加等于目标值。
  2. 两遍哈希表法:遍历数组,将每个数及其索引存入哈希表,然后再次遍历数组,查找 target - nums[i]​​ 是否在哈希表中。
  3. 一遍哈希表法:遍历数组,对于每个数,查找 target - nums[i]​​ 是否在哈希表中,如果在,直接返回结果;如果不在,将当前数存入哈希表。

截图为Go语言的测试

Go语言实现 - 一遍哈希表法

package main
func twoSum(nums []int, target int) []int {hashTable := make(map[int]int)for i, num := range nums {complement := target - numif index, ok := hashTable[complement]; ok {return []int{index, i}}hashTable[num] = i}return nil
}

C++实现

#include <vector>
#include <unordered_map>class Solution {
public:std::vector<int> twoSum(std::vector<int>& nums, int target) {std::unordered_map<int, int> hashTable;for (int i = 0; i < nums.size(); ++i) {int complement = target - nums[i];if (hashTable.find(complement) != hashTable.end()) {return {hashTable[complement], i};}hashTable[nums[i]] = i;}return {};}
};

算法分析

  • 时间复杂度:O(n),其中 n 是数组中的元素数量。我们只遍历了包含有 n 个元素的列表两次。在哈希表中的操作时间复杂度为 O(1)。
  • 空间复杂度:O(n),所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 n 个元素。
    这个Go语言实现的代码简单易懂,效率较高,适合解决这类问题。

image

排序和双指针法

  1. 首先,创建一个数组,包含原始数组的元素和它们的索引。

  2. 然后,根据数组元素对数组进行排序。

  3. 使用两个指针,一个从开始(最小元素)的位置,另一个从结束(最大元素)的位置。

  4. 比较两个指针指向的元素之和与目标和:

    • 如果和等于目标和,返回两个元素的索引。
    • 如果和小于目标和,移动左侧指针,使它指向一个更大的数。
    • 如果和大于目标和,移动右侧指针,使它指向一个更小的数。
      这种方法的关键在于,排序后我们可以使用双指针高效地找到两个数,使得它们的和等于目标和。

Go语言实现 - 排序和双指针法

package main
import ("sort"
)
type Pair struct {Value intIndex int
}
func twoSum(nums []int, target int) []int {pairs := make([]Pair, len(nums))for i, num := range nums {pairs[i] = Pair{Value: num, Index: i}}sort.Slice(pairs, func(i, j int) bool {return pairs[i].Value < pairs[j].Value})left, right := 0, len(nums)-1for left < right {sum := pairs[left].Value + pairs[right].Valueif sum == target {return []int{pairs[left].Index, pairs[right].Index}} else if sum < target {left++} else {right--}}return nil
}

C++

#include <vector>
#include <algorithm>
#include <utility>class Solution {
public:std::vector<int> twoSum(std::vector<int>& nums, int target) {std::vector<std::pair<int, int>> numWithIndex;for (int i = 0; i < nums.size(); ++i) {numWithIndex.push_back({nums[i], i});}std::sort(numWithIndex.begin(), numWithIndex.end());int left = 0, right = nums.size() - 1;while (left < right) {int sum = numWithIndex[left].first + numWithIndex[right].first;if (sum == target) {return {numWithIndex[left].second, numWithIndex[right].second};} else if (sum < target) {++left;} else {--right;}}return {};}
};

算法分析

  • 时间复杂度:O(nlogn),其中 n 是数组中的元素数量。排序的时间复杂度是 O(nlogn),双指针遍历的时间复杂度是 O(n)。
  • 空间复杂度:O(n),我们需要一个额外的数组来存储元素和它们的索引。
    这种方法在空间复杂度上与哈希表方法相同,但时间复杂度稍高,因为它需要排序。然而,这种方法在不允许修改原数组或需要保持元素原始顺序的情况下可能更有用。

image

暴力法

  1. 使用两个嵌套循环遍历数组中的所有元素对。
  2. 对于每一对元素,检查它们的和是否等于目标和。
  3. 如果找到一对元素的和等于目标和,返回这两个元素的索引。
    这种方法的时间复杂度是 O(n^2),因为它需要对数组中的每一对元素进行一次检查。

Go语言实现 - 暴力法

package main
func twoSum(nums []int, target int) []int {for i := 0; i < len(nums); i++ {for j := i + 1; j < len(nums); j++ {if nums[i] + nums[j] == target {return []int{i, j}}}}return nil
}

C++

#include <vector>class Solution {
public:std::vector<int> twoSum(std::vector<int>& nums, int target) {for (int i = 0; i < nums.size(); ++i) {for (int j = i + 1; j < nums.size(); ++j) {if (nums[i] + nums[j] == target) {return {i, j};}}}return {};}
};

算法分析

  • 时间复杂度:O(n^2),其中 n 是数组中的元素数量。最坏的情况下,我们需要遍历每个元素与其他元素的组合。
  • 空间复杂度:O(1),我们只需要常数级别的额外空间来存储索引。
    暴力法是一种简单直接的方法,但是对于大型数据集来说,它的效率不高。在实际应用中,通常会优先考虑使用哈希表或排序和双指针法来解决这类问题。

image

二分搜索法

  1. 首先,对数组进行排序,并创建一个新数组来保存排序后元素的原始索引。
  2. 对于数组中的每个元素,使用二分搜索查找 target - nums[i]​。
  3. 如果找到,确保两个元素的原始索引不同,然后返回它们的原始索引。
    这种方法的关键在于,排序后我们可以使用二分搜索高效地找到第二个数。

Go语言实现 - 二分搜索法

package main
import ("sort"
)
func twoSum(nums []int, target int) []int {indexes := make([]int, len(nums))for i := range nums {indexes[i] = i}sort.Slice(indexes, func(i, j int) bool {return nums[indexes[i]] < nums[indexes[j]]})for i := 0; i < len(nums); i++ {left, right := i+1, len(nums)-1complement := target - nums[indexes[i]]for left <= right {mid := left + (right-left)/2if nums[indexes[mid]] == complement {return []int{indexes[i], indexes[mid]}} else if nums[indexes[mid]] < complement {left = mid + 1} else {right = mid - 1}}}return nil
}

C++

#include <vector>
#include <algorithm>
#include <numeric>class Solution {
public:std::vector<int> twoSum(std::vector<int>& nums, int target) {std::vector<int> indexes(nums.size());std::iota(indexes.begin(), indexes.end(), 0);std::sort(indexes.begin(), indexes.end(), [&nums](int i, int j) { return nums[i] < nums[j]; });for (int i = 0; i < nums.size(); ++i) {int left = i + 1, right = nums.size() - 1;int complement = target - nums[indexes[i]];while (left <= right) {int mid = left + (right - left) / 2;if (nums[indexes[mid]] == complement) {return {indexes[i], indexes[mid]};} else if (nums[indexes[mid]] < complement) {left = mid + 1;} else {right = mid - 1;}}}return {};}
};

算法分析

  • 时间复杂度:O(nlogn),其中 n 是数组中的元素数量。排序的时间复杂度是 O(nlogn),二分搜索的时间复杂度是 O(logn),总共进行了 n 次二分搜索。
  • 空间复杂度:O(n),我们需要一个额外的数组来保存索引。
    二分搜索法在空间复杂度上与哈希表方法相同,但时间复杂度稍高,因为它需要排序。这种方法在不允许修改原数组或需要保持元素原始顺序的情况下可能更有用。然而,对于"两数之和"这个问题,哈希表法通常是更优的选择,因为它的时间复杂度更低。

image

C++的实现

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/492224.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JS基础之常用调试语句

JS基础之常用调试语句 目录 JS基础之常用调试语句打印控制台consolelog日志级别error错误信息warn警告级别 警告框alert输入框prompt 打印控制台console log日志级别 <script>let name "张三"console.log(name) </script>error错误信息 <script&g…

二维动态规划题目(未完)

1.最小路径和&#xff08;力扣LCR 99题&#xff09; 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 说明&#xff1a;一个机器人每次只能向下或者向右移动一步。 方法一&#xff1a;暴力递归…

软考46-上午题-【数据库】-数据查询语言DQL1

一、SQL数据查询功能 SELECT语句的语法如下&#xff1a; 【注意】&#xff1a; 使用DISTINCT选项可以去重&#xff1b; form子句中出现多个基本表或视图时&#xff0c;系统首先执行笛卡尔积操作。 下面的查询示例均以这些表为基础 1-1、投影查询-SELECT 【回顾】&#xff1a;…

自定义神经网络三之梯度和损失函数激活函数

文章目录 前言梯度概述梯度下降算法梯度下降的过程 optimize优化器 梯度问题梯度消失梯度爆炸 损失函数常用的损失函数损失函数使用原则 激活函数激活函数和损失函数的区别激活函数Relu-隐藏层激活函数Sigmoid和Tanh-隐藏层Sigmoid函数Tanh&#xff08;双曲正切&#xff09; &l…

基于Pytorch的猫狗图片分类【深度学习CNN】

猫狗分类来源于Kaggle上的一个入门竞赛——Dogs vs Cats。为了加深对CNN的理解&#xff0c;基于Pytorch复现了LeNet,AlexNet,ResNet等经典CNN模型&#xff0c;源代码放在GitHub上&#xff0c;地址传送点击此处。项目大纲如下&#xff1a; 文章目录 一、问题描述二、数据集处理…

单片机一个32位地址对应多大的存储空间?

文章目录 文字图片 文字 一个地址是4个字节 一个地址对应一个字节的存储空间&#xff08;无论8位、16位、32位单片机&#xff09; 学过C语言的都知道&#xff1a;指针就是地址&#xff0c;因此指针也是4个字节 图片 这两张是工作的笔记、主要看第二张&#xff0c;左边是代码&…

第7.1章:StarRocks性能调优——查询分析

目录 一、查看查询计划 1.1 概述 1.2 查询计划树 1.3 查看查询计划的命令 1.3 查看查询计划 二、查看查询Profile 2.1 启用 Query Profile 2.2 获取 Query Profile 2.3 Query Profile结构与详细指标 2.3.1 Query Profile的结构 2.3.2 Query Profile的合并策略 2.…

单链表详解

个人主页&#xff1a;不爱学英文的码字机器-CSDN博客 收录合集&#xff1a;《数据结构》 在本篇博客中&#xff0c;我们将深入探讨单链表的定义、实现和应用。 本篇博客将用C语言实现的单链表进行讲解&#xff0c;通过一段代码一段讲解来逐个详细讲解&#xff0c;深入了解单链表…

Java编程与数据库技术:疫情居家办公的坚实后盾

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

基于自适应波束成形算法的matlab性能仿真,对比SG和RLS两种方法

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于自适应波束成形算法的matlab性能仿真,对比SG和RLS两种方法. 2.测试软件版本以及运行结果展示 MATLAB2022a版本运行 3.核心程序 ........................…

字符函数和字符串函数(C语言进阶)(三)

目录 前言 接上篇&#xff1a; 1.7 strtok 1.8 strerror 1.9 字符分类函数 总结 前言 C语言中对字符和字符串的处理是很频繁的&#xff0c;但是c语言本身是没有字符串类型的&#xff0c;字符串通常放在常量字符串中或着字符数组中。 字符串常量适用于那些对它不做修改的字…

某电力铁塔安全监测预警系统案例分享

项目概述 电力铁塔是承载电力供应的重要设施&#xff0c;它的安全性需要得到可靠的保障。但是铁塔一般安装在户外&#xff0c;分布广泛&#xff0c;且有很多安装在偏远地区&#xff0c;容易受到自然、人力的影响和破环。因此需要使用辅助的方法实时监控铁塔的安全状态&#xff…