每日一题

  • 3. 无重复字符的最长子串
    • 题目
    • 总体思路
    • 代码
  • 1.两数之和
    • 题目
    • 总体思路
    • 代码
  • 15. 三数之和
    • 题目
    • 总体思路
    • 代码

2025.8.15

3. 无重复字符的最长子串

题目

给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。

示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成

总体思路

用布尔数组的滑动窗口法

  • 使用固定大小数组标记字符是否出现过:
    这里 visited[128] 对应 ASCII 码字符。
    true 表示该字符在当前窗口内已经出现。
  • 维护滑动窗口:
    left 表示窗口左边界,right 表示窗口右边界。
    窗口 [left, right] 中保证没有重复字符。
  • 遇到重复字符时移动左指针:
    如果 visited[ch] == true,说明当前字符已在窗口中。
    移动左指针 left,同时将左边字符标记清除,直到窗口中不再有重复字符。
  • 更新窗口状态:
    将当前字符 ch 标记为已出现。
    更新 maxLen 为窗口长度 right-left+1。
  • 时间复杂度:
    每个字符最多进出窗口一次 → O(n)
    空间复杂度 O(1),因为固定数组大小 128。

用哈希表的滑动窗口法

  • 使用哈希表记录窗口中字符出现次数:
    键是字符,值是出现次数(这里最多是 1)。
    动态维护当前窗口的字符集合。
  • 维护滑动窗口的左右指针:
    i 是左指针,rk 是右指针。
    左指针每移动一次,移除窗口最左边的字符。
    右指针尽可能右移,保证窗口内没有重复字符。
  • 右指针移动条件:
    rk+1 < n 防止越界
    m[s[rk+1]] == 0 窗口中没有重复字符
    满足条件时,右指针 rk 右移,并将字符计入哈希表。
  • 更新答案:
    窗口 [i, rk] 是以 i 为左边界的最长无重复字符子串
    ans = max(ans, rk-i+1)。
  • 时间复杂度:
    每个字符进出窗口一次 → O(n)
    空间复杂度 O(min(n, charset)),因为哈希表动态存储字符。

代码

golang

// 使用滑动窗口法查找无重复字符的最长子串长度
func lengthOfLongestSubstring(s string) int {visited := [128]bool{} // ASCII 码范围的字符标记数组left, maxLen := 0, 0for right := 0; right < len(s); right++ {ch := s[right]// 如果当前字符已经在窗口内出现过,则移动左指针直到移除该字符for visited[ch] {visited[s[left]] = falseleft++}// 标记该字符已出现visited[ch] = true// 更新最大长度if right-left+1 > maxLen {maxLen = right - left + 1}}return maxLen
}func lengthOfLongestSubstring(s string) int {// 哈希表,记录窗口中字符出现次数m := map[byte]int{}n := len(s) // 字符串长度// 右指针,初始值为 -1// 相当于在字符串左边界左侧,还没有开始移动rk, ans := -1, 0// 遍历每个字符,i 是左指针for i := 0; i < n; i++ {if i != 0 {// 左指针向右移动一格// 移除窗口最左边的字符delete(m, s[i-1])}// 不断向右移动右指针 rk// 条件:// 1. rk+1 < n,防止越界// 2. m[s[rk+1]] == 0,窗口中没有重复字符for rk+1 < n && m[s[rk+1]] == 0 {rk++              // 右指针右移一格m[s[rk]]++        // 把该字符加入窗口}// 此时窗口 [i, rk] 是一个最长无重复字符子串// 更新答案ans = max(ans, rk-i+1)}return ans
}

1.两数之和

题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。

示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案

总体思路

暴力求解法

  • 枚举所有可能的两个数:
    用两层 for 循环,第一层遍历第一个数 nums[i],第二层遍历第二个数 nums[j]。
  • 检查是否满足条件:
    如果 nums[i] + nums[j] == target 并且 i != j,说明找到了一对符合条件的下标。
  • 立即返回结果:
    直接返回这两个下标 [i, j]。
  • 时间复杂度:
    外层循环 O(n),内层循环 O(n) → 总体 O(n²)。
    空间复杂度 O(1),因为没有额外的数据结构。

哈希表优化法

  • 使用哈希表记录已访问过的数值:
    建一个 map[int]int,键是数值,值是该数值在 nums 中的下标。
  • 单次遍历寻找匹配:
    遍历 nums 时,对于当前数 num,计算它的“互补数” target - num。
  • 检查互补数是否已出现过:
    如果互补数在哈希表中,说明之前某个元素的值 + 当前值正好等于 target,直接返回这两个下标。
  • 否则记录当前数:
    把当前的 (数值 → 下标) 存进哈希表,供后续元素匹配。
  • 时间复杂度:
    仅需单次遍历 O(n)。
    空间复杂度 O(n),用来存储哈希表。

代码

golang

//暴力求解
func twoSum(nums []int, target int) []int {for i:=0;i<len(nums);i++{for j:=1;j<len(nums);j++{if nums[i]+nums[j]==target && i!=j{return []int{i,j}}}}return nil
} //哈希
func twoSum(nums []int, target int) []int {hash:=map[int]int{}   //键为“某个数值”,值为“该数值在 nums 中的下标”。for i, num:=range nums {   //range 遍历切片,i 是下标,num 是当前元素的拷贝if p, ok :=hash[target-num];ok{   //互补数是否已经出现过。如果出现过,ok == true,p 是互补数的下标。return []int{p,i}}hash[num]=i   //把“当前数值 → 当前下标”记进表里,供后面的元素来匹配。}return nil
}

2025.8.16

15. 三数之和

题目

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105

总体思路

双指针法

  • 排序
    先对数组 nums 排序。
    排序后可以利用双指针移动来快速缩小范围。
  • 固定第一个数 nums[i]
    从左到右依次枚举 i。
    如果 nums[i] > 0,因为数组已经排序,后面的数都 ≥0,不可能再凑出 0,可以直接停止。
    如果 nums[i] 跟前一个数相同,就跳过,避免重复解。
  • 左右指针搜索另外两个数
    设定 left := i+1,right := n-1。
    计算三数之和 sum := nums[i] + nums[left] + nums[right]。
    • 如果 sum == 0,说明找到一组解。
      保存三元组 [nums[i], nums[left], nums[right]]。
      然后移动 left++ 和 right–,并且跳过重复值。
    • 如果 sum < 0,说明和太小,需要增大和 → left++。
    • 如果 sum > 0,说明和太大,需要减小和 → right–。
  • 继续枚举下一个 i
    直到遍历完成,返回所有解。

暴力求解(三重循环)

  • 枚举所有三元组
    用三层循环,依次固定下标 i、j、k,保证它们互不相等。
    枚举所有可能的组合 (nums[i], nums[j], nums[k])。
  • 判断和是否为 0
    如果 nums[i] + nums[j] + nums[k] == 0,就认为它是一个符合要求的三元组。
  • 避免重复
    直接三重循环会出现重复解,比如 [−1,0,1] 可能通过不同的下标组合出现多次。
    常见做法是:
    • 先对数组排序。
    • 再用一个 map 或 set(在 Go 里用 map[[3]int]bool)来记录已经出现过的三元组。
  • 保存结果:
    把符合条件的三元组存入结果切片 [][]int,最后返回。

代码

golang

//双指针
import "sort"
func threeSum(nums []int) [][]int {sort.Ints(nums)  //排序n := len(nums)//left, right := 1, len(nums)-1ret := make([][]int, 0)seen := make(map[[3]int]bool)for i:=0; i<n-2; i++ {// 如果 nums[i] > 0,后面全是非负数,不可能和为0,直接breakif nums[i] > 0 {break}// 跳过重复的i,避免结果重复if i > 0 && nums[i] == nums[i-1] {continue}left, right := i+1, n-1for left<right {sum := nums[i] + nums[left] + nums[right]if sum == 0 {key:=[3]int{nums[i],nums[left],nums[right]}if !seen[key] {seen[key]=trueret = append(ret,[]int{nums[i],nums[left],nums[right]})}left++right--}else if sum < 0 {left++ // 和偏小,左指针右移} else {right-- // 和偏大,右指针左移}}}return ret}//暴力求解超时了。。。bunengyong
import "sort"
func threeSum(nums []int) [][]int {sort.Ints(nums)    //先排序,便于存入集合时用有序三元组作为去重键res := make([][]int, 0)// 使用 map 记录已经出现过的三元组(用固定顺序的[3]int作为key)seen :=make(map[[3]int]bool)for i:=0;i<len(nums)-2;i++ {for j:=i+1;j<len(nums)-1;j++ {for k:=j+1;k<len(nums);k++ {if(nums[i]+nums[j]+nums[k]==0){key := [3]int{nums[i],nums[j],nums[k]}//去重if !seen[key]{   seen[key]=trueres = append(res, []int{nums[i], nums[j], nums[k]})}}}}}return res
}

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

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

相关文章

sharding-jdbc读写分离配置

一主两从&#xff0c;爆红是正常的&#xff0c;不知为啥 spring:shardingsphere:datasource:names: ds_master,ds_s1,ds_s2ds_master:type: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.135.100:3306/gmall_produ…

【大模型核心技术】Dify 入门教程

文章目录一、Dify 是什么二、安装与部署2.1 云端 SaaS 版&#xff08;快速入门&#xff09;2.2 私有化部署&#xff08;企业级方案&#xff09;三、界面导航与核心模块3.1 控制台概览3.2 核心功能模块详解3.2.1 知识库&#xff08;RAG 引擎&#xff09;3.2.2 工作流编排3.2.3 模…

homebrew 1

文章目录brew(1) – macOS&#xff08;或 Linux&#xff09;上缺失的包管理器概要描述术语表基本命令install *formula*uninstall *formula*listsearch \[*text*|/*text*/]命令alias \[--edit] \[*alias*|*alias**command*]analytics \[*subcommand*]autoremove \[--dry-run]bu…

设计索引的原则有哪些?

MySQL 索引设计的核心原则是 在查询性能与存储成本之间取得平衡。以下是经过实践验证的 10 大设计原则及具体实现策略&#xff1a;一、基础原则原则说明示例/反例1. 高频查询优先为 WHERE、JOIN、ORDER BY、GROUP BY 频繁出现的列建索引✅ SELECT * FROM orders WHERE user_id1…

使用影刀RPA实现快递信息抓取

最近公司项目有个需求&#xff0c;要求抓取快递单号快递信息&#xff0c;比如签收地点、签收日期等。该项目对应的快递查询网站是一个国外的网站&#xff0c;他们有专门的快递平台可以用于查询。该平台提供了快递接口进行查询&#xff0c;但需要付费。同时也提供了免费的查询窗…

蚁剑--安装、使用

用途限制声明&#xff0c;本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具&#xff0c;严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果&#xff0c;作者及发布平台不承担任何责任。渗透测试涉及复杂技…

Varjo XR虚拟现实军用车辆驾驶与操作培训

Patria基于混合现实的模拟器提供了根据现代车辆乘员需求定制的培训&#xff0c;与传统显示设置相比&#xff0c;全新的模拟解决方案具有更好的沉浸感和更小的物理空间需求。Patria是芬兰领先的国防、安全和航空解决方案提供商。提供尖端技术和全面的培训系统&#xff0c;以支持…

Java 10 新特性及具体应用

目录 1. 局部变量类型推断&#xff08;JEP 286&#xff09; 2. 不可修改集合&#xff08;JEP 269&#xff09; 3. 并行全垃圾回收&#xff08;JEP 307&#xff09; 4. 应用类数据共享&#xff08;JEP 310&#xff09; 5. 线程局部管控&#xff08;JEP 312&#xff09; 总结…

【力扣 Hot100】刷题日记

D8 全排列(非回溯法) 全排列原题链接 在刷leetcode的时候&#xff0c;看到这道题目并没法使用像STL的next_permutation方法&#xff0c;感叹C便利的同时&#xff0c;又惋惜Java并没有类似的API&#xff0c;那我们只能从原理入手了&#xff0c;仿写此算法。 其实回溯法更应该…

JetPack系列教程(七):Palette——让你的APP色彩“飞”起来!

JetPack系列教程&#xff08;七&#xff09;&#xff1a;Palette——让你的APP色彩“飞”起来&#xff01; 各位开发小伙伴们&#xff0c;还在为APP的配色发愁吗&#xff1f;别担心&#xff0c;今天咱们就来聊聊JetPack家族里的“色彩魔法师”——Palette&#xff01;这个神奇的…

力扣hot100 | 矩阵 | 73. 矩阵置零、54. 螺旋矩阵、48. 旋转图像、240. 搜索二维矩阵 II

73. 矩阵置零 力扣题目链接 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]…

ARC与eARC是什么?主要用在哪?

在家庭影音设备不断升级的今天&#xff0c;人们对音视频体验的要求越来越高。无论是追剧、玩游戏还是观看电影大片&#xff0c;很多用户不再满足于电视自带的扬声器&#xff0c;而是希望借助回音壁、功放或家庭影院系统&#xff0c;获得更加震撼的沉浸式声音体验。一、ARC是什么…

解锁JavaScript性能优化:从理论到实战

文章目录 前言 一、常见性能瓶颈剖析 二、实战案例与优化方案 (一)DOM 操作优化案例​ (二)事件绑定优化案例​ (三)循环与递归优化案例​ (四)内存管理优化案例​ 三、性能优化工具介绍 总结 前言 性能优化的重要性 在当今数字化时代,Web 应用已成为人们生活和工作…

结构化记忆、知识图谱与动态遗忘机制在医疗AI中的应用探析(上)

往期相关内容推荐: 基于Python的多元医疗知识图谱构建与应用研究(上)

XSS攻击:从原理入门到实战精通详解

一、XSS攻击基础概念1.1 什么是XSS攻击 XSS&#xff08;Cross-Site Scripting&#xff0c;跨站脚本攻击&#xff09;是一种将恶意脚本注入到可信网站中的攻击手段。当用户访问被注入恶意代码的页面时&#xff0c;浏览器会执行这些代码&#xff0c;导致&#xff1a;用户会话被劫…

Leetcode 14 java

今天复习一下以前做过的题目&#xff0c;感觉是忘光了。 160. 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数…

用 FreeMarker 动态构造 SQL 实现数据透视分析

在 ERP、BI 等系统中&#xff0c;数据透视分析&#xff08;Pivot Analysis&#xff09;是非常常见的需求&#xff1a;用户希望按任意维度&#xff08;如门店、时间、商品分类等&#xff09;进行分组统计&#xff0c;同时选择不同的指标&#xff08;如 GMV、订单数、客单价等&am…

13.深度学习——Minst手写数字识别

第一部分——起手式 import torch from torchvision import datasets, transforms import torch.nn as nn import torch.nn.functional as F import torch.optim as optimuse_cuda torch.cuda.is_available()if use_cuda:device torch.device("cuda") else: device…

【JAVA高级】实现word转pdf 实现,源码概述。深坑总结

之前的需求做好后,需求,客户突发奇想。要将生成的word转为pdf! 因为不想让下载文档的人改动文档。 【JAVA】实现word添加标签实现系统自动填入字段-CSDN博客 事实上这个需求难度较高,并不是直接转换就行的 word文档当中的很多东西都需要处理 public static byte[] gener…

数据驱动测试提升自动化效率

测试工程师老王盯着满屏重复代码叹气&#xff1a;“改个搜索条件要重写20个脚本&#xff0c;这班加到啥时候是个头&#xff1f;” 隔壁组的小李探过头&#xff1a;“试试数据驱动呗&#xff0c;一套脚本吃遍所有数据&#xff0c;我们组上周测了300个组合都没加班&#xff01;”…