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 - num
        if 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 int
	Index 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)-1
	for left < right {
		sum := pairs[left].Value + pairs[right].Value
		if 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)-1
		complement := target - nums[indexes[i]]
		for left <= right {
			mid := left + (right-left)/2
			if 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

规则持久化(Sentinel)

规则持久化 基于Nacos配置中心实现推送 引入依赖 <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId> </dependency> 流控配置文件 [{"resource":"/order/flow",…

vue+nodejs+uniapp婚纱定制婚庆摄影系统 微信小程序 springboot+python

目前移动互联网大行其道&#xff0c;人人都手中拿着智能机&#xff0c;手机手机&#xff0c;手不离机&#xff0c;如果开发一个用在手机上的程序软件&#xff0c;那是多么的符合潮流&#xff0c;符合管理者和客户的理想。本次就是开发婚庆摄影小程序&#xff0c;有管理员&#…

k8s学习笔记-基础概念

&#xff08;作者&#xff1a;陈玓玏&#xff09; deployment特别的地方在于replica和selector&#xff0c;docker根据镜像起容器&#xff0c;pod控制容器&#xff0c;job、cronjob、deployment控制pod&#xff0c;job做离线任务&#xff0c;pod大多一次性的&#xff0c;cronj…

【蓝桥杯】拓扑排序

一.拓扑排序 1.定义&#xff1a; 设G&#xff08;V&#xff0c;E&#xff09;是一个具有n个顶点的有向图&#xff0c;V中的顶点序列称为一个拓扑序列&#xff0c;当且仅当满足下列条件&#xff1a;若从顶点到有一条路径&#xff0c;则在顶点序列中顶点必在之前。 2.基本思想…

Vue+SpringBoot打造音乐偏好度推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 音乐档案模块2.1.2 我的喜好模块2.1.3 每日推荐模块2.1.4 通知公告模块 2.2 用例图设计2.3 实体类设计2.4 数据库设计 三、系统展示3.1 登录注册3.2 音乐档案模块3.3 音乐每日推荐模块3.4 通知公告模…

【安装】CentOS 7 使用 OUI 图形界面安装 Oracle Database 19.3

需安装使用 X Server 协议的软件&#xff08;如 Xorg&#xff09;和如桌面图形软件&#xff08;Gnome 或 KDE&#xff09;。 使用 root 用户执行&#xff1a; # curl -o oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm https://yum.oracle.com/repo/OracleLinux/OL7/l…

istio系列教程

istio学习记录——安装https://suxueit.com/article_detail/otVbfI0BWZdDRfKqvP3Gistio学习记录——体验bookinfo及可视化观测https://suxueit.com/article_detail/o9VdfI0BWZdDRfKqlv0r istio学习记录——kiali介绍https://suxueit.com/article_detail/pNVbfY0BWZdDRfKqX_0K …

在Node.js中如何实现用户身份验证和授权

当涉及到构建安全的应用程序时&#xff0c;用户身份验证和授权是至关重要的一环。在Node.js中&#xff0c;我们可以利用一些流行的库和技术来实现这些功能&#xff0c;确保我们的应用程序具有所需的安全性。本篇博客将介绍如何在Node.js中实现用户身份验证和授权。 用户身份验…

“激发无限创意:在线图片制作,点亮你的视觉灵感!“

在数字时代&#xff0c;图片已经成为我们表达创意、分享故事和展示个性的重要方式。然而&#xff0c;你是否曾因为缺乏专业的设计技能或繁琐的制作流程而感到困扰&#xff1f;现在&#xff0c;有了在线图片制作平台&#xff0c;释放你的创意灵感变得前所未有的简单和方便&#…

福特锐界2021plus 汽车保养手册

福特锐界2021plus汽车保养手册两页&#xff0c;零部件保养要求&#xff0c;电子版放这里方便查询&#xff1a;

8-pytorch-损失函数与反向传播

b站小土堆pytorch教程学习笔记 根据loss更新模型参数 1.计算实际输出与目标之间的差距 2.为我们更新输出提供一定的依据&#xff08;反向传播&#xff09; 1 MSEloss import torch from torch.nn import L1Loss from torch import nninputstorch.tensor([1,2,3],dtypetorch.fl…

MySQL——基础内容

目录 第01章_数据库概述 关系型数据库(RDBMS)——表、关系模型 非关系型数据库(非RDBMS) 表、记录、字段 表的关联关系 一对一关联 一对多关系 多对多 自我引用 第02章_MySQL环境搭建 登录命令 常用命令 show databases; create database use 数据库名 show tables 第03章…

五种多目标优化算法(MOCS、MOFA、NSWOA、MOAHA、MOPSO)性能对比(提供MATLAB代码)

一、5种多目标优化算法简介 多目标优化算法是用于解决具有多个目标函数的优化问题的一类算法。其求解流程通常包括以下几个步骤&#xff1a; 1. 定义问题&#xff1a;首先需要明确问题的目标函数和约束条件。多目标优化问题通常涉及多个目标函数&#xff0c;这些目标函数可能…

云原生之容器编排实践-kubectl get pod -A没有coredns

背景 前面搭建的3节点 Kubernetes 集群&#xff0c;其实少了一个组件&#xff1a; CoreDNS &#xff0c;这也是我后面拿 ruoyi-cloud 项目练手时&#xff0c;部署了 MySQL 和 Nacos 服务后才意识到的&#xff1a;发现Nacos无法通过服务名连接MySQL&#xff0c;这里 Nacos 选择…

Mac OS 搭建C++开发环境【已解决】

Mac OS 搭建C开发环境 文章目录 Mac OS 搭建C开发环境一、安装命令行工具&#xff1a;二、安装vscode三、安装gcc3.1 安装Homebrew3.2 安装gcc3.3 修改配置 四、更改VSCode默认编译器五、安装gdb六、安装Cmake && git七、编译运行 本地环境&#xff1a; Mac OS Sonoma …

Python中回调函数的理解与应用

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 目录 前言 回调函数的概念 回调函数的基本用法 回调函数的实现方式 1 使用函数 2 使用类方法 3 使用类实…

QWidget: Must construct a QApplication before a QWidget 13:25:48: 程序异常结束。

QWidget: Must construct a QApplication before a QWidget 13:25:48: 程序异常结束。 你的插件是release&#xff0c;而你用了debug模式、

一元函数微分学——刷题(19

目录 1.题目&#xff1a;2.解题思路和步骤&#xff1a;3.总结&#xff1a;小结&#xff1a; 1.题目&#xff1a; 2.解题思路和步骤&#xff1a; 题目给的是个复合函数&#xff0c;因此需要根据复合函数求得原本f’(x)的表达式&#xff1a; 3.总结&#xff1a; 题目给的是个…

Java EE改名Jakarta EE,jakarta对程序开发的影响

一、前言 很多Java程序员在使用新版本的Spring6或者springboot3版本的时候&#xff0c;发现了一些叫jakarta的包。我在阅读开源工作流引擎camunda源代码的时候&#xff0c;也发展了大量jakarta的工程包。 比如&#xff1a;camunda的webapps编译工程就提供了2种方式javax和jaka…

linux系统---httpd

目录 Internet的起源 一、http协议——超文本传输协议 1.http相关概念 二、HTTP请求访问的完整过程 1、 建立连接 2、 接收请求 3、 处理请求 常用请求Method: GET、POST、HEAD、PUT、DELETE、TRACE、OPTIONS 3.1 常见的HTTP方法 3.2 GET和POST比较 4、访问资源 …