常见算法题整理

2023-10-27

算法题:

  • 数据结构:数组、链表、字符串、树、数学、栈、hash表、图
  • 动态规划、中心扩散、回溯算法、递归、迭代、贪心算法、
  • 从整体到细节,自顶向下,从抽象到具体的框架思维是通用的,不只是学习数据结构和算法,学习其他任何知识都是高效的。

一、数组:

技巧:

  • 双指针

二、链表:

技巧:

  • 链表问题一般先定义一个哑结点,将特殊清除处理掉

链表反转

private  Node reverse(Node node) {
        Node pre = null, cur = node, tem = null;
        while (cur != null) {
            tem = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tem;
        }
        return pre;
    }

2. 两数相加

难度中等 6174

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 特判:
        if(l1==null)return l2;
        if(l2==null)return l1;

        int carry=0;
        ListNode dummy =new ListNode(0);// 定义个哑结点,便于处理
        ListNode pre=dummy; // 指向哑结点的地址、最终返回pre.next;

        while(l1!=null && l2!=null){
            int sum =l1.val+l2.val+carry;
            carry =sum/10;
            ListNode node =new ListNode(sum%10);
            dummy.next=node;
            l1=l1.next;
            l2=l2.next;
            dummy=dummy.next;
        }
        while(l1!=null){
            int sum =l1.val+carry;
            carry =sum/10;
            ListNode node =new ListNode(sum%10);
            dummy.next=node;
            l1=l1.next;
            dummy=dummy.next;
        }
       while(l2!=null){
            int sum =l2.val+carry;
            carry =sum/10;
            ListNode node =new ListNode(sum%10);
            dummy.next=node;
            l2=l2.next;
            dummy=dummy.next;
        }
        if(carry>0){
            dummy.next=new ListNode(carry); 
        }
        return pre.next;
    }
}
  • 看清题意,有时候需要做链表的反转。

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

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // 方式1: 遍历一遍,统计元素个数总和 ,再遍历
        // 方式2: 快慢指针

        // 定义一个哑结点,使得链表中所有的结点都有前驱结点
        ListNode dummy = new ListNode(0,head);
        // 定义快慢指针都指向哑结点
        ListNode fast=dummy, slow=dummy;
        // 让快指针先往前移动 n+1 步
        for(int i=0;i<n+1;i++){
            fast=fast.next;
        }
        // 同时移动快慢指针,直到快指针指向null
        while(fast!=null){
            fast=fast.next;
            slow=slow.next;
        }
        // 不清理要删除元素所占的空间。
        // slow.next=slow.next.next;
        // 清理待删除元素所占的空间
        ListNode delNode =slow.next;
        slow.next=delNode.next;
        delNode.next=null;
        
        return dummy.next;
    }
}

寻找链表的中间结点:

// 快慢指针,慢指针一次走一步,快指针一次走两步。最终慢指针指向就为中间结点
private ListNode endOfFirstHalf(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

141. 环形链表

public class Solution {
    public boolean hasCycle(ListNode head) {
        Set<ListNode> seen = new HashSet<ListNode>();
        while (head != null) {
            if (!seen.add(head)) {
                return true;
            }
            head = head.next;
        }
        return false;
    }
}

面试题 02.06. 回文链表

  • 其中包括获取中间结点的方法
  • 链表反转的方法。
  • 最终达到
class Solution {
    public boolean isPalindrome(ListNode head) {
// 方式3:反转后半段链表,然后比较前后半段链表的值
        // 1、通过快慢指针,找出链表的中间结点,慢指针的next结点为后半部分的开始
        ListNode firstTail = getFirstHalf(head);
        if(firstTail==null) return true ;
        //2、反转后半部分链表
        ListNode nextHalf= reversal(firstTail.next);
        //3、比较将原链表和后半部分值比较。(不同return false, 相同返回true)
        while(nextHalf!=null){
            if(head.val!=nextHalf.val){
                return false;
            } else{
                head=head.next;
                nextHalf=nextHalf.next;
            }
        }
        return true;
    }
    // 获取链表中间结点的方法
    private ListNode getFirstHalf(ListNode head){
        ListNode fast =head,slow =head;
        while(fast!=null&&fast.next!=null&& fast.next.next!=null){
            fast =fast.next.next;
            slow=slow.next;
        }
        return slow;
    }
    // 链表反转
    private ListNode reversal(ListNode node){
        ListNode pre = null, cur=node,tem=null;
        while(cur!=null){
            tem =cur.next;
            cur.next=pre;
            pre=cur;
            cur=tem;
        } 
        return pre;
    }
}

三、字符串:

  • 字符串问题一般转换成char数组,去操作数组,省的每次操作字符串的str.charAt(i)

1、验证子串是否为回文串

// char[] charArr =str.toCharArray();// 字符串转换成char数组

private static boolean validateSubstring(char[] charArr, int left ,int right){
  while(left<right){
    if(charArr[left]!=charArr[right]){
      return false;
    }
    left++;
    right--;
  }
  return true;
}

5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。

示例 2:

输入:s = “cbbd”
输出:“bb”
示例 3:

输入:s = “a”
输出:“a”
示例 4:

输入:s = “ac”
输出:“a”

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

class Solution {
    public String longestPalindrome(String s) {
        // 特判
        if(null==s || s.length()<2) return s;
        // 中心扩散法
        int res =1; //最大长度
        int ll=0;   //最大回文串的左指针
        int rr=0;   //最大回文串的右指针
        //将字符串转成char数组,不在循环中去使用str.charAt(i)
        char[] chArr =s.toCharArray();

        // 开始遍历char数组
        for(int i =0; i<chArr.length; i++){
            // 以i为中心向两边扩散,寻找最长子串(通俗:回文串为奇数长度i为中心)
            int l =i-1;
            int r =i+1;

            while(l>=0 && r<chArr.length && chArr[l]==chArr[r]){
                int len =r-l+1;
                if(len>res){
                    res=len;
                    ll=l;
                    rr=r;
                }
                l--;
                r++;
            }
            // 以i为左指针,i+1为右指针(通俗:回文串为偶数长度)
            l=i;
            r=i+1;
            while(l>=0 && r<chArr.length && chArr[l]==chArr[r]){
                int len =r-l+1;
                if(len>res){
                    res=len;
                    ll=l;
                    rr=r;
                }
                l--;
                r++;
            }
        } 
        return s.substring(ll,rr+1);
    }
}

四、树:

技巧:

  • 递归最简单,一般树的问题都可以通过递归来解决。(需要再学下迭代,迭代是显示维护一个栈)
  • 前序遍历:根左右;中序遍历:左根右;后序遍历:左右根。

94. 二叉树的中序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        // 中序遍历:左 根 右
        List<Integer> list = new ArrayList<Integer>();
        leftOrder(root,list);
        return list;
    }
    private void leftOrder(TreeNode node, List list){
        if(null==node) return;

        leftOrder(node.left,list);
        list.add(node.val);
        leftOrder(node.right,list);

    }
}

五、栈:

六、Hash表

七、图

八、动态规划(labuladong)

动态规划的特点:

  • 重叠子问题
  • 状态转义方程(最关键)
  • 最优子结构

题型:

  • 求最值
  • 核心:穷举:不要小看暴力穷举

解题套路:

  • 明确【状态】
  • 明确【选择】
  • 明确dp函数、数组的定义
  • 明确base case。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RsFw2FXi-1622290180636)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524104147868.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqdphKC2-1622290180639)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524104228806.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lMB5LyEx-1622290180641)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524104255133.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iv9SXKeI-1622290180645)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524110029673.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-onKZYvFS-1622290180646)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524110123303.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4RaL0PV6-1622290180648)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524110307321.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DuZMyq2H-1622290180649)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524111455743.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lSizQQ5a-1622290180649)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210523234630863.png)]

  • 空间换时间。引入数组备忘录,占用数组大小的空间。

  • 自底向上:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EtPHrtHP-1622290180650)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524130837926.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QXdBtZBI-1622290180651)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524130804245.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tdIKRMnf-1622290180652)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524131015765.png)]

  • 优秀的算法都是慢慢演变来的 ,就像系统架构一样,不是一开始就很优,都是慢慢演变的

509:斐波那契数列

class Solution {
    public int fib(int n) {
        // 方式1:直接递归 ,但是时间复杂度较高,多了很多重复的计算。
         /*// 方式2:带备忘录的递归。将所有计算过的值缓存下来,递归中直接返回。(自顶向下推,然后自底向上回溯)
       // 初始化备忘录。
         int[] notes =new int[n+1];
        // 进行带备忘录的递归。
        return helper(notes, n);*/

       /* // 方式3:dp数组迭代法 (自底向上)
        if(n==0) return 0;
        int[] dp =new int[n+1];
        // base case 
        dp[0]=0; dp[1]=1;
        // 状态转移
        for(int i=2; i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];*/
        //方式4: 优化空间复杂度,求第n个数,其实只需要知道他的前两个数就可以了 ,
        // 因此可以定义两个变量去表示它的前两个数的值,依次来优化空间复杂度
        if(n==0) return 0;
        int pre=0,curr=1;
        for(int i=2;i<=n;i++){
            int sum=pre+curr;
            pre =curr;
            curr=sum;
        }
        return curr;
    }
    private int helper(int[] notes,int n){
        if(n==0|| n==1) return n; //base case
        if(notes[n]!=0) return notes[n];
        notes[n] =helper(notes,n-1)+helper(notes,n-2);
        return notes[n];
    }
}

322. 零钱兑换

  • 动态规划 是用于求最值的问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l8LPzpXZ-1622290180652)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524131921580.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-inO9cJ24-1622290180653)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524131725872.png)]

  • 自顶向下的递归(带备忘录)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDrON8qK-1622290180654)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524132417304.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PfYzUeuZ-1622290180655)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524132746801.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-byRez0zV-1622290180655)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524133054887.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4xp2AyzG-1622290180656)(%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98.assets/image-20210524133112429.png)]

动态规划问题的本质:

  • 1、如何穷举
    • 写出状态转移方程,暴力穷举所有可行解。
  • 2、如何聪明的穷举
    • 用备忘录消除重叠子问题,写出自动向下解法
    • 进一步,可以写出自动向下解法
    • 再进一步,可能可以优化空间复杂度
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常见算法题整理 的相关文章

随机推荐

  • linux学习(五)解决github网页无法进入

    文章目录 前言 1 问题 2 解决 前言 准确来说这个内容不属于linux学习 但是使用git管理代码时需要用到 这里就提前准备一下 1 问题 github网页无法刷出来 一直转圈 2 解决 step1 找到C Windows System
  • 取整函数_6个Excel取整函数技巧,让你的数据规规矩矩!

    Excel技巧是十分神奇的 可以用来娱乐 也能用来工作 更重要的是可以工作效率 不管是在什么地方 最不讨人喜欢的就是有小数点的数据 那怎么办了 今天就来教给大家6个超简单又很实用的Excel取整函数 1 CEILING 函数取整 CEILI
  • windows10编译open3d 0.13

    目录 写在前面 准备 获取源码 cmake cmake版本 开始cmake 1 命令行 2 cmake gui 编译 安装 测试 完 写在前面 1 环境 win10 visual studio2019 cmake3 22 0 rc1 下载源
  • C语言浮点数存储规则

    1 浮点型数据类型 float double long double 目前常用的类型为float 用于存储单精度浮点数和双精度浮点数 浮点数使用IEEE 电气和电子工程协会 格式 浮点类型的32位浮点数具有 4 个字节 包括一个符号位 一个
  • 【FPGA学习】状态机实现UART通信

    文章目录 前言 一 数据帧结构 二 接收模块 2 1 状态设置 2 1 状态跳转 2 2 奇校验 2 3 数据输出 三 发送模块 3 1 状态跳转 3 2 数据输出 四 顶层模块 总结 前言 在之前的文章中 FPGA学习 实例一 Cyclo
  • 7、Java入门教程【面向对象】

    面向对象是Java编程的核心概念 如果不能充分了解面向对象的思想 那么会给你在实际的项目开发过程中 带来很多业务设计上的困扰 一 构造器 我们在设计完一个类 在使用这个类去创建对象实例的时候 有些场景是需要对实例做初始化操作的 那么Java
  • 雅思备考资料整理

    单纯想整理一下自己使用过的素材 梳理一下自己学习到的经验 万一以后还需要考呢 一 听力 何琼听力网课 王陆语料库 王陆建议听写前先过一遍单词 进行同义词整理 听写到后面几章速度很快 写下来很耽误时间也跟不上 我是边听脑子里就同时反应单词怎么
  • java自定义数组_java创建自定义类的数组

    今天在学图论的最小生成树 开始一直在想是用邻接矩阵还是关联矩阵来表示图 但是发现这样都会有好多空间浪费 于是我就自定义一个边的类 里面包含了权值 关联的端点1 端点2 和图的表示字母 发现我想创建11条边 Bian new Bian 11
  • 第6章 K8s基础篇-资源调度

    杜宽老师k8s课程学习记录 6 1 Replication Controller和ReplicaSet Replication Controller 复制控制器 RC 和ReplicaSet 复制集 RS 是两种简单部署Pod的方式 因为在
  • python全栈开发优势条件_Python全栈开发-day01-初识python

    一 Python学习的大致框架 1 linux基础 计算机以及日后我们开发的程序放置的服务器的简单操作 2 Python开发 1 Python基础 2 网络编程 断点续传 一般情况下不需要我们自己开发 3 web框架 用于写网站 4 设计模
  • 等保测评:SQLServer操作超时

    一 说明 本文说的是等级保护1 0中SQLServer数据库操作超时的内容 实际在SQLServer中有很多种超时选项 很容易将其混为一谈 本文将尽力将之说清楚 二 操作超时的意义 操作超时在sqlserver数据库中可能包含好几个意思 2
  • BeagleBone 嵌入式操作

    特点 BeagleBone Black 是一个嵌入式系统 能够运行完整的 GNU Linux 发行版 例如 Debian 或 Ubuntu BeagleBone Black 具有强大的分发功能 并配有易于扩展的嵌入式板卡 是一款允许用户构建
  • JAVA浏览器控件JxBrowser v7.3上线!最新API文档打包带走!

    JxBrowser是将基于Chromium的浏览器与Java应用程序集成 以处理和显示HTML5 CSS3 JavaScript Flash等 近日 JxBrowser v7 3发布上线 支持最新macOS Catalina 支持Java1
  • QT 信号和槽的使用笔记

    目录 信号和槽介绍 回调机制 信号槽机制 信号 槽 信号槽和直接调用效率问题 信号和槽的使用对比 QT5 写法 QT4 写法 总结 信号和槽介绍 信号与插槽机制 提供对象间的通信机制 可以取代原始的回调和消息映射机制 信号与槽是迅速的 类型
  • 计算机网络--基础篇(IP地址,端口号,协议,五元组,封装分用,客户端,服务器)

    目录 一 IP地址 1 IP地址的概念及格式 2 IP地址的编址方法阶段 3 IP地址的分类 二 端口号 1 定义 2 格式 三 协议 三要素 四 五元组 五 发送端和接收端 六 封装分用 七 客户端和服务器 1 服务端 2 客户端 一 I
  • MyBatis查询单表返回List

    本来以为把List
  • python dict 写入 json 文件 编码问题

    esports 0 subject list sign 2 name aa desc 听阿红的 sign 3 name bb desc 成绩啊啊啊 id 1
  • idea 模块名后面有个中括号别名(1)

    步骤 第一步 第二步 为什么不直接改名字 最近项目正在从Springboot改造成SpringCloud微服务架构 所以会涉及到新增模块的情况 这里我直接复制了项目中的一个 模块 并且通过修改文件夹名的方式命名该模块 之后该模块名后面出现了
  • IntelliJ IDEA 2019(Ultimate Edition)激活方法

    IntelliJ IDEA 2019 Ultimate Edition 激活方法 https blog csdn net halen001 article details 81137092
  • 常见算法题整理

    算法题 数据结构 数组 链表 字符串 树 数学 栈 hash表 图 动态规划 中心扩散 回溯算法 递归 迭代 贪心算法 从整体到细节 自顶向下 从抽象到具体的框架思维是通用的 不只是学习数据结构和算法 学习其他任何知识都是高效的 一 数组