【CodeTop】TOP 100 刷题 21-30

文章目录

  • 21. 螺旋矩阵
    • 题目描述
    • 代码与解题思路
  • 22. 反转链表 II
    • 题目描述
    • 代码与解题思路
  • 23. 相交链表
    • 题目描述
    • 代码与解题思路
  • 24. 合并 K 个升序链表
    • 题目描述
    • 代码与解题思路
  • 25. 字符串相加
    • 题目描述
    • 代码与解题思路
  • 26. 最长递增子序列
    • 题目描述
    • 代码与解题思路
  • 27. 重排链表
    • 题目描述
    • 代码与解题思路
  • 28. 环形链表 II
    • 题目描述
    • 代码与解题思路
  • 29. 接雨水
    • 题目描述
    • 代码与解题思路
  • 30. 删除链表的倒数第 N 个结点
    • 题目描述
    • 代码与解题思路

21. 螺旋矩阵

题目链接:54. 螺旋矩阵

题目描述

代码与解题思路

func spiralOrder(matrix [][]int) (res []int) {
    if len(matrix) == 0 {
        return res
    }
    top, bottom, left, right := 0, len(matrix)-1, 0, len(matrix[0])-1
    for top < bottom && left < right {
        for i := left; i < right; i++ { res = append(res, matrix[top][i]) }
        for i := top; i < bottom; i++ { res = append(res, matrix[i][right]) }
        for i := right; i > left; i-- { res = append(res, matrix[bottom][i]) }
        for i := bottom; i > top; i-- { res = append(res, matrix[i][left]) }
        left++
        top++
        right--
        bottom--
    }
    if top == bottom { // 剩余一行
        for i := left; i <= right; i++ { res = append(res, matrix[top][i]) }
    } else if left == right { // 剩余一列
        for i := top; i <= bottom; i++ { res = append(res, matrix[i][right]) }
    }
    return res
}

这个方法是最好理解且最好记忆的,直接根据题意来模拟这样一个过程,一圈一圈的遍历来实现,最后再处理一下剩余的行/列即可。

22. 反转链表 II

题目链接:92. 反转链表 II

题目描述

代码与解题思路

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseBetween(head *ListNode, left int, right int) *ListNode {
    phead := &ListNode{Next: head}
    prev := phead
    for i := 0; i < left-1; i++ { // 找到起始位置
        prev = prev.Next
    }
    cur := prev.Next
    for i := 0; i < right-left; i++ { // 反转链表
        tmp := cur.Next
        cur.Next = tmp.Next
        tmp.Next = prev.Next
        prev.Next = tmp
    }
    return phead.Next
}

核心就在链表反转的逻辑,如果忘记了就画图再复习一遍。

23. 相交链表

题目链接:160. 相交链表

题目描述

代码与解题思路

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func getIntersectionNode(headA, headB *ListNode) *ListNode {
    curA, curB := headA, headB
    for curA != curB {
        if curA == nil {
            curA = headB
        } else {
            curA = curA.Next
        }
        if curB == nil {
            curB = headA
        } else {
            curB = curB.Next
        }
    }
    return curA
}

题解区很多用三目运算符的,没必要,if else 就很清晰了,两个指针每次遍历各走一步,如果为空就从对方的链表从头开始,最后相等只有两种情况:

  1. 他们在相交的地方相遇了
  2. 他们都走到各自的 nil 了

24. 合并 K 个升序链表

题目链接:23. 合并 K 个升序链表

题目描述

代码与解题思路

func mergeKLists(lists []*ListNode) *ListNode {
    n := len(lists)
    if n == 0 {
        return nil
    }
    if n == 1 {
        return lists[0]
    }
    left := mergeKLists(lists[:n/2])
    right := mergeKLists(lists[n/2:])
    return mergeTwoLists(left, right)
}

func mergeTwoLists(list1, list2 *ListNode) *ListNode {
    phead := &ListNode{}
    cur := phead
    for list1 != nil && list2 != nil {
        if list1.Val < list2.Val {
            cur.Next = list1
            list1 = list1.Next
        } else {
            cur.Next = list2
            list2 = list2.Next
        }
        cur = cur.Next
    }
    if list1 != nil {
        cur.Next = list1
    } else {
        cur.Next = list2
    }
    return phead.Next
}

这道题我曾经的做法是暴力全部遍历一遍,塞进数组中,然后用库函数排序,然后再将数组转化成链表的形式,采用的是暴力匹配的方式,之后也可以和面试官聊聊这个思路

而现在新学习到的解法是使用分治的解法,通过递归分治,将链表数组对半拆分,直到拆分成两个子数组后调用合并两个链表的方法(这个方法实现起来也不难)将每一个子链表合并成升序链表,最后组合成一个大的升序链表,非常巧妙的分治算法

多学,多用,多思考。

25. 字符串相加

题目链接:415. 字符串相加

题目描述

代码与解题思路

func addStrings(num1 string, num2 string) (ans string) {
    len1, len2 := len(num1)-1, len(num2)-1
    carry := 0
    for len1 >= 0 || len2 >= 0 {
        x, y := 0, 0
        if len1 >= 0 {
            x = int(num1[len1] - byte('0'))
        }
        if len2 >= 0 {
            y = int(num2[len2] - byte('0'))
        }
        sum := x+y+carry
        ans += strconv.Itoa(sum%10)
        carry = sum/10
        len1--
        len2--
    }
    if carry != 0 {
        ans += "1"
    }
    return reverse(ans)
}

func reverse(ans string) string {
    tmp := []byte(ans)
    l, r := 0, len(tmp)-1
    for l < r {
        tmp[l], tmp[r] = tmp[r], tmp[l]
        l++
        r--
    }
    return string(tmp)
}

这道题不难,但是有很多需要注意的地方

  1. 字符串相加这类题型的思路,从后往前遍历,累加成一个字符串,最后反转
  2. reverse 函数的编写需要熟练,用 go 的小缺陷,有些方法需要手撕
  3. strconv.Itoa(int),这个 int 转 string 的方法必须得记住,不然这道题铁定做不出来,go 只能借助调用来 int 转 string

26. 最长递增子序列

题目链接:300. 最长递增子序列

题目描述

代码与解题思路

func lengthOfLIS(nums []int) int {
    ans := 1
    dp := make([]int, len(nums))
    for i, _ := range nums { dp[i]=1 }
    for i := 1; i < len(nums); i++ {
        for j := 0; j < i; j++ {
            if nums[i] > nums[j] { // 只要遇到, 对应的 dp 数组位置的值就+1
                dp[i] = max(dp[j]+1, dp[i])
            }
        }
        ans = max(ans, dp[i])
    }
    return ans
}

能写出动态规划的方法就行了,如果忘了就去看题解区的图解,二分法就不要想了,能做出来就不错了。。。

27. 重排链表

题目链接:143. 重排链表

题目描述

代码与解题思路

第一种方法,用数组存节点,然后通过数组的随机访问性质来重排

func reorderList(head *ListNode)  {
    tmp := []*ListNode{}
    cur := head
    for cur != nil {
        tmp = append(tmp, cur)
        cur = cur.Next
    }
    i, j := 0, len(tmp)-1
    for i < j {
        tmp[i].Next = tmp[j]
        i++
        if i == j {
            break
        }
        tmp[j].Next = tmp[i]
        j--
    }
    tmp[i].Next = nil
}

第二种方法:

  1. 取中点(快慢指针,获得了中点的指针)
  2. 反转右半部分链表(这样就能 O(N) 的进行从后往前的遍历了)
  3. 再通过起点指针和中点指针的配合切换节点位置
func reorderList(head *ListNode)  {
    // 取中点
    slow, fast := head, head
    for fast != nil && fast.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
    }
    // 反转右半链表
    var pre *ListNode = nil
    var cur = slow
    for cur != nil {
        nxt := cur.Next
        cur.Next = pre
        pre = cur
        cur = nxt
    }
    // 完成链表重排
    left, right := head, pre
    for right.Next != nil {
        tmpl := left.Next
        tmpr := right.Next

        left.Next = right
        right.Next = tmpl
        
        left = tmpl
        right = tmpr
    }
}

到时候如果面试遇到这道题目,可以把第一种思路讲出来,然后再讲第二种思路,最后实现第二种思路,最需要注意的是链表的反转,我突然链表反转老是写不出来,好难受,之后多刷几遍链表反转怎么写,一定要把链表的反转给练熟了

28. 环形链表 II

题目链接:142. 环形链表 II

题目描述

代码与解题思路

func detectCycle(head *ListNode) *ListNode {
    slow, fast := head, head
    for {
        if fast == nil || fast.Next == nil { // 走到尾了,证明没环
            return nil
        }
        slow = slow.Next
        fast = fast.Next.Next
        if slow == fast { // 相遇了,证明有环
            break
        }
    }
    fast = head // 让 fast 回头重新遍历
    for slow != fast {
        slow = slow.Next
        fast = fast.Next
    }
    return fast
}

这道题很操蛋,是一个数学问题,是需要证明的,我是证明不出来这东西,如果真在面试遇到了,我也就只能背代码了。。没办法,平等的对每一个数学问题白痴。。。

29. 接雨水

题目链接:42. 接雨水

题目描述

代码与解题思路

func trap(height []int) (ans int) {
    st := []int{}
    for i, v := range height {
        for len(st) > 0 && height[st[len(st)-1]] < v {
            cur := st[len(st)-1]
            st = st[:len(st)-1]
            if len(st) == 0 {
                break
            }
            l := st[len(st)-1]
            r := i
            h := min(height[l], height[r])-height[cur] // 用矮的柱子去减最低位的值
            ans += (r-l-1)*h
        }
        st = append(st, i)
    }
    return ans
}

经典单调栈题目,多刷几遍就熟练了,非常经典的单调栈思路,栈中的值是不断递减的,如果遇到比栈顶大的值,就证明柱子把这片区域围上了。

30. 删除链表的倒数第 N 个结点

题目链接:19. 删除链表的倒数第 N 个结点

题目描述

代码与解题思路

func removeNthFromEnd(head *ListNode, n int) *ListNode {
    phead := &ListNode{Next: head}
    slow, fast := phead, head
    for n > 0 { // 让 fast 指针先走 n 步
        fast = fast.Next
        n--
    }
    for fast != nil { // 同时遍历,这样 slow 指针就会离链表尾 n 个身位
        slow = slow.Next
        fast = fast.Next
    }
    slow.Next = slow.Next.Next // 删除节点
    return phead.Next
}

非常经典的快慢指针思路,让快指针先走 n 步,快慢指针同时往后走,那慢指针就能停在结尾倒数第 n 个节点上,然后执行删除操作即可。

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

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

相关文章

删除list中除最后一个之外所有的数据

1.你可以新建一个list List<Integer> listnew ArrayList<>();int i0;while (i<100){list.add(i);}List<Integer> subList list.subList(list.size()-1, list.size());System.out.println("原list大小--"list.size());System.out.println("…

渗透测试考核(靶机1)

信息收集 主机发现 nbtscan -r 172.16.17.0/24 发现在局域网内&#xff0c;有两台主机名字比较可疑&#xff0c;177和134&#xff0c;猜测其为目标主机&#xff0c;其余的应该是局域网内的其他用户&#xff0c;因为其主机名字比较显眼&#xff0c;有姓名的拼音和笔记本电脑的…

CentOS 7 部署 Nacos (单机版)

CentOS 7 部署 Nacos &#xff08;单机版&#xff09; 1. 下载 Nacos 安装包 历史版本&#xff1a;https://github.com/alibaba/nacos/releases/ 我选的是 2.1.0 版本&#xff0c;https://github.com/alibaba/nacos/releases/download/2.1.0/nacos-server-2.1.0.tar.gz 2. …

flink源码分析之功能组件(四)-slotpool组件II

简介 本系列是flink源码分析的第二个系列&#xff0c;上一个《flink源码分析之集群与资源》分析集群与资源&#xff0c;本系列分析功能组件&#xff0c;kubeclient&#xff0c;rpc&#xff0c;心跳&#xff0c;高可用&#xff0c;slotpool&#xff0c;rest&#xff0c;metrics&…

亚马逊云科技基于 Polygon 推出首款 Amazon Managed Blockchain Access,助 Web3 开发人员降低区块链节点运行成本

2023 年 11 月 26 日&#xff0c;亚马逊 (Amazon) 旗下 Amazon Web Services&#xff08;Amazon&#xff09;在其官方博客上宣布&#xff0c;Amazon Managed Blockchain (AMB) Access 已支持 Polygon Proof-of-Stake(POS) 网络&#xff0c;并将满足各种场景的需求&#xff0c;包…

PC端ssh连接到Android手机的Termux部署http服务器

1. 下载并安装Termux至Android手机 Releases termux/termux-app (github.com) https://github.com/termux/termux-app/releases 2. 手机端启动Termux&#xff0c;安装openssh #更新仓库 pkg up pkg install openssh #安装好后&#xff0c;启动sshd sshd问题1&#xff1a;如…

vscode非常好用的扩展插件

1、Code Spell Checker&#xff1a; 帮助我们检查单词是否拼写错误&#xff0c;检查规则遵循驼峰拼写法。 2、Color Highlight&#xff1a;高亮显示颜色值 3、Svg Preview&#xff1a; 实时预览svg图片&#xff08;修改width、height、fill等值来实时查看效果&#xff09; 4、…

常见的AI安全风险(数据投毒、后门攻击、对抗样本攻击、模型窃取攻击等)

文章目录 数据投毒&#xff08;Data Poisoning&#xff09;后门攻击&#xff08;Backdoor Attacks&#xff09;对抗样本攻击&#xff08;Adversarial Examples&#xff09;模型窃取攻击&#xff08;Model Extraction Attacks&#xff09;参考资料 数据投毒&#xff08;Data Poi…

基于ssm的汽车论坛管理系统设计与实现

基于ssm的汽车论坛管理系统设计与实现 摘要&#xff1a;信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题…

python爬虫AES案例:某招聘网站

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 一、找出需要加密的参数 js运行 atob(‘aHR0cHM6Ly93d3cua2Fuemh1bi5jb20vc2VhcmNoLz9xdWVyeT1weXRob24mdHlwZT0w’) 拿到网址…

Webshell流量分析

Webshell流量分析 常见的一句话木马: asp一句话 <%eval request("pass")%> aspx一句话 <%@ Page Language="Jscript"%><%eval(Request.Item["pass"],"unsafe");%> php一句话 <?php @eval($_POST["pass&…

SDK emulator directory is missing

要进行uniapp真机测试&#xff0c;不得不安装配置一下安卓开发环境 &#xff0c;搞一个模拟器。。。然后又是各种坑。。对比来对比去还是IOS的环境使用着舒服&#xff0c;XCODE下载好&#xff0c;一切重点就是在编码了。。 安卓这个脑残货呀&#xff0c;哎&#xff0c;各种安装…

Win中Redis部署与配置

1.下载msi版本 下载传送门 2.双击next-->next安装安装 3.密码配置以及开机自启 在配置文件中配置相应配置进行配置密码以及端口和ip port 6379指定 Redis 监听端口&#xff0c;默认端口为 6379&#xff0c;作者在自己的一篇博文中解释了为什么选用 6379 作为默认端口&…

【傻瓜级JS-DLL-WINCC-PLC交互】7.​C#直连PLC并读取PLC数据

思路 JS-DLL-WINCC-PLC之间进行交互&#xff0c;思路&#xff0c;先用Visual Studio创建一个C#的DLL控件&#xff0c;然后这个控件里面嵌入浏览器组件&#xff0c;实现JS与DLL通信&#xff0c;然后DLL放入到WINCC里面的图形编辑器中&#xff0c;实现DLL与WINCC的通信。然后PLC与…

实现一个高并发的Redis分布式锁

1. 无锁场景 下面是一个扣减库存逻辑, 由于查库存和扣减库存两个操作不是原子的,明显存在并发超卖问题 // 假设初始库存200GetMapping("/stock")public String stock(RequestParam(value "name", defaultValue "World") String name) {String…

基于docker的onlyoffice使用--运行JavaSpringExample

背景 我之前看到有开源项目很好地集成了onlyoffice&#xff0c;效果要比kkfilepreview好&#xff08;应当说应用场景不太一样&#xff09;。本文是在window10环境&#xff0c;安装完Docker Desktop的基础上运行onlyoffice&#xff0c;并利用官网JavaSpringExample进行了集成。 …

福德植保无人机:农业科技的新篇章

一、引言随着科技的不断发展&#xff0c;无人机技术在许多领域中都得到了广泛的应用。近年来&#xff0c;福德植保无人机在农业领域大放异彩&#xff0c;成为了现代化农业的重要一环。本篇文章将为您详细介绍福德植保无人机的优势、特点以及未来发展趋势。 二、福德植保无人机的…

Linux socket编程(8):shutdown和close的区别详解及例子

在Linux中有两种操作可以终止socket间的进程通信&#xff1a;close和shutdown。但这两种函数在使用时有着不同的行为和效果。在网络编程中&#xff0c;正确地选择和使用这些操作至关重要&#xff0c;因为它们直接影响着通信的结束和资源的释放。本文将介绍close和shutdown函数&…

Thrift RPC Java、Go、PHP使用例子

文章目录 1、Thrift RPC介绍1.1、Protocol 支持的数据传输协议1.2、Transport 支持的数据传输方式1.3、Server 支持的服务模型1.4、IDL语法数据类型1.5、开发步骤 2、接口定义文件2.1、创建接口定义文件2.2、生成对应平台语言代码2.2.1、下载生成工具2.2.2、生成各平台语言代码…

单片机----串行通信

目录 串行通信的两种方式 串行通信的传输模式 串行通信的错误校验 1.奇偶校验 2.代码和校验 3.循环冗余码校验 串行口结构 串行口控制寄存器SCON 特殊功能寄存器PCON 串行口的4种工作方式 方式0&#xff1a; &#xff08;1&#xff09;方式0的发送过程 &#xff0…