妈妈再也不用担心我的学习了!看完教你一招教你吃透数据结构链表!

面试java开发被问最多的“cookie、session、token”问题,安排! 面试java开发被问最多的“cookie、session、token”问题,安排!前言发展历程Cookie1.什么是Cookie2.Cookie的机制3.Cookie的属性Expires修改或者删除CookieCookie的域名Cookie的路径4.应用Session1.什么是Session2.Session实现原理3.session创建和销毁Token1.什么是Token2.Token的原理3.Token的使用项目依赖 pom.xml自定义注解用户实体类、及查询serviceToken生成拦截器拦截to. 阅读详情

在这里插入图片描述


本文会从递归反转整个单链表开始拓展

递归反转整个链表

先直接看实现代码:

ListNode reverse(ListNode head) {
    if (head.next == null) return head;
    ListNode last = reverse(head.next);
    head.next.next = head;
    head.next = null;
    return last;
}

对于递归算法,最重要的就是明确递归函数的定义。具体来说,我们的 reverse 函数定义是这样的:

输入一个节点 head,将「以 head 为起点」的链表反转,并返回反转之后的头结点。

不过其中有两个地方需要注意:

1、递归函数要有 base case,也就是这句:

if (head.next == null) return head;

意思是如果链表只有一个节点的时候反转也是它自己,直接返回即可。

2、当链表递归反转之后,新的头结点是 last,而之前的 head 变成了最后一个节点,别忘了链表的末尾要指向 null:

head.next = null;

反转链表前 N 个节点

实现一个这样的函数:

// 将链表的前 n 个节点反转(n <= 链表长度)
ListNode reverseN(ListNode head, int n)

比如说对于下图链表,执行 reverseN(head, 3):

image

解决思路和反转整个链表差不多,只要稍加修改即可:

ListNode successor = null; // 后驱节点

// 反转以 head 为起点的 n 个节点,返回新的头结点
ListNode reverseN(ListNode head, int n) {
    if (n == 1) { 
        // 记录第 n + 1 个节点
        successor = head.next;
        return head;
    }加入Java开发交流君样:484138291一起吹水聊天

    // 以 head.next 为起点,需要反转前 n - 1 个节点
ListNode last = reverseN(head.next, n - 1);
head.next.next = head;
// 让反转之后的 head 节点和后面的节点连起来
head.next = successor;
return last;
}

具体的区别:

1、base case 变为 n == 1,反转一个元素,就是它本身,同时要记录后驱节点。

2、刚才我们直接把 head.next 设置为 null,因为整个链表反转后原来的 head 变成了整个链表的最后一个节点。但现在 head 节点在递归反转之后不一定是最后一个节点了,所以要记录后驱 successor(第 n + 1 个节点),反转之后将 head 连接上。

image

反转链表的一部分

给一个索引区间 [m,n](索引从 1 开始),仅仅反转区间中的链表元素。

ListNode reverseBetween(ListNode head, int m, int n)

首先,如果 m == 1,就相当于反转链表开头的 n 个元素嘛,也就是我们刚才实现的功能:

ListNode reverseBetween(ListNode head, int m, int n) {
    // base case
    if (m == 1) {
        // 相当于反转前 n 个元素
        return reverseN(head, n);
    }
    // ...
}

如果 m != 1 怎么办?如果我们把 head 的索引视为 1,那么我们是想从第 m 个元素开始反转对吧;如果把 head.next 的索引视为 1 呢?那么相对于 head.next,反转的区间应该是从第 m - 1 个元素开始的;那么对于 head.next.next 呢……

区别于迭代思想,这就是递归思想,所以我们可以完成代码:

ListNode reverseBetween(ListNode head, int m, int n) {
    // base case
    if (m == 1) {
        return reverseN(head, n);
    }
    // 前进到反转的起点触发 base case
    head.next = reverseBetween(head.next, m - 1, n - 1);
    return head;
}

值得一提的是,递归操作链表并不高效。和迭代解法相比,虽然时间复杂度都是 O(N),但是迭代解法的空间复杂度是 O(1),而递归解法需要堆栈,空间复杂度是 O(N)。

K个一组翻转链表

image

对这个链表调用 reverseKGroup(head, 2),即以 2 个节点为一组反转链表:

image

如果我设法把前 2 个节点反转,那么后面的那些节点怎么处理?后面的这些节点也是一条链表,而且规模(长度)比原来这条链表小,这就叫子问题。

image

我们可以直接递归调用 reverseKGroup(cur, 2),因为子问题和原问题的结构完全相同,这就是所谓的递归性质。

发现了递归性质,就可以得到大致的算法流程:

1、先反转以 head 开头的 k 个元素。

image

2、将第 k + 1 个元素作为 head 递归调用 reverseKGroup 函数。

image

3、将上述两个过程的结果连接起来。

image

如果最后的元素不足 k 个,就保持不变。这就是 base case

首先,我们要实现一个 reverse 函数反转一个区间之内的元素

/** 反转区间 [a, b) 的元素,注意是左闭右开 */
ListNode reverse(ListNode a, ListNode b) {
    ListNode pre, cur, nxt;
    pre = null; cur = a; nxt = a;
    // while 终止的条件改一下就行了
    while (cur != b) {
        nxt = cur.next;
        cur.next = pre;
        pre = cur;
        cur = nxt;
    }
    // 返回反转后的头结点
    return pre;
}

现在我们迭代实现了反转部分链表的功能,接下来就按照之前的逻辑编写 reverseKGroup 函数即可:

ListNode reverseKGroup(ListNode head, int k) {
    if (head == null) return null;
    // 区间 [a, b) 包含 k 个待反转元素
    ListNode a, b;
    a = b = head;
    for (int i = 0; i < k; i++) {
        // 不足 k 个,不需要反转,base case
        if (b == null) return head;
        b = b.next;
    }
    // 反转前 k 个元素
    ListNode newHead = reverse(a, b);
    // 递归反转后续链表并连接起来
    a.next = reverseKGroup(b, k);
    return newHead;
}

image

整个函数递归完成之后就是这个结果:

image

判断回文链表

寻找回文串的核心思想是从中心向两端扩展:

string palindrome(string& s, int l, int r) {
    // 防止索引越界
    while (l >= 0 && r < s.size()
            && s[l] == s[r]) {
        // 向两边展开
        l--; r++;
    }
    // 返回以 s[l] 和 s[r] 为中心的最长回文串
    return s.substr(l + 1, r - l - 1);
}

判断一个字符串是不是回文串就简单很多,不需要考虑奇偶情况,只需要「双指针技巧」,从两端向中间逼近即可:

bool isPalindrome(string s) {
    int left = 0, right = s.length - 1;
    while (left < right) {
        if (s[left] != s[right])
            return false;
        left++; right--;
    }
    return true;
}

判断回文单链表

借助二叉树后序遍历的思路,不需要显式反转原始链表也可以倒序遍历链表

void traverse(TreeNode root) {
    // 前序遍历代码
    traverse(root.left);
    // 中序遍历代码
    traverse(root.right);
    // 后序遍历代码
}

借助二叉树后序遍历的思路,不需要显式反转原始链表也可以倒序遍历链表

void traverse(TreeNode root) {
    // 前序遍历代码
    traverse(root.left);
    // 中序遍历代码
    traverse(root.right);
    // 后序遍历代码
}

链表其实也可以有前序遍历和后序遍历:

void traverse(ListNode head) {
    // 前序遍历代码
    traverse(head.next);
    // 后序遍历代码
}

如果我想正序打印链表中的val值,可以在前序遍历位置写代码;反之,如果想倒序遍历链表,就可以在后序遍历位置操作:

/* 倒序打印单链表中的元素值 */
void traverse(ListNode head) {
    if (head == null) return;
    traverse(head.next);
    // 后序遍历代码
    print(head.val);
}

其实可以稍作修改,模仿双指针实现回文判断的功能:

// 左侧指针
ListNode left;

boolean isPalindrome(ListNode head) {
    left = head;
    return traverse(head);
}

boolean traverse(ListNode right) {
    if (right == null) return true;
    boolean res = traverse(right.next);
    // 后序遍历代码
    res = res && (right.val == left.val);
    left = left.next;
    return res;
}

这么做的核心逻辑实际上就是把链表节点放入一个栈,然后再拿出来,这时候元素顺序就是反的,只不过我们利用的是递归函数的堆栈而已。

优化空间复杂度

1、先通过「双指针技巧」中的快慢指针来找到链表的中点:

    ListNode slow, fast;
slow = fast = head;
        while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        }
// slow 指针现在指向链表中点

2、如果 fast指针没有指向 null,说明链表长度为奇数,slow还要再前进一步:

if (fast != null)
        slow = slow.next;

image

3、从slow开始反转后面的链表,现在就可以开始比较回文串了:

    ListNode left = head;
    ListNode right = reverse(slow);

while (right != null) {
        if (left.val != right.val)
        return false;
        left = left.next;
        right = right.next;
        }
        return true;

image

把上面 3 段代码合在一起就高效地解决这个问题了,其中reverse函数很容易实现:

ListNode reverse(ListNode head) {
    ListNode pre = null, cur = head;
    while (cur != null) {
        ListNode nxt = cur.next;
        cur.next = pre;
        pre = cur;
        cur = nxt;
    }
    return pre;
}

整体代码如下:

// 这个方法通过将链表中间后边的链表反转,因为后边的链表往前遍历不好遍历,所以反转之后往后遍历就相当于原来的链表往前遍历,这样就可以方便的和前边的链表作比较了
public boolean isPalindrome(ListNode head) {
    ListNode slow = findMidNxt(head);
    ListNode left = head;
    // 将中间后边的链表反转之后,这样就可以方便的遍历反转后的链表来判断和左边的链表是否相同了
    ListNode right = reverse(slow);
    while(right!=null) {
        if(right.val!=left.val) {
            return false;
        }
        right = right.next;
        left = left.next;
    }
    // left = head;
    return true;
}

// 反转链表
public ListNode reverse(ListNode head) {
    ListNode pre,cur,nxt;
    pre = null;cur = head;nxt =head;
    while(cur!=null) {
        nxt = cur.next;
        cur.next = pre;
        pre = cur;
        cur = nxt;
    }
    return pre;
}
// 通过快慢指针找到中间的那个节点的后边那个节点
public ListNode findMidNxt(ListNode head) {
    ListNode slow,fast;
    slow = head;fast = head;
    while(fast!=null&&fast.next!=null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    // 如果fast指针没有指向null,说明链表长度为奇数,slow还要再前进一步
    if(fast !=null) {
        slow = slow.next;
    }
    return slow;
}

这种解法虽然高效,但破坏了输入链表的原始结构,能不能避免这个瑕疵呢?

其实这个问题很好解决,关键在于得到p, q这两个指针位置:

image

只要在函数 return 之前加一段代码即可恢复原先链表顺序:

p.next = reverse(q);

总结

寻找回文串是从中间向两端扩展,判断回文串是从两端向中间收缩。对于单链表,无法直接倒序遍历,可以造一条新的反转链表,可以利用链表的后序遍历,也可以用栈结构倒序处理单链表。

具体到回文链表的判断问题,由于回文的特殊性,可以不完全反转链表,而是仅仅反转部分链表,将空间复杂度降到 O(1)。

分类: [数据结构]
最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

可以的话请给我一个三连支持一下我哟???【获取资料】

关于Springboot集成Swagger到底是什么?请看这篇分说! 关于Springboot集成Swagger到底是什么?请看这篇分说!集成SwaggerSwagger简介springboot集成Swagger1、新建一个springboot项目,添加web框架2、添加相关依赖3、编写controller层编写Swagger的配置类4、编写Swagger的配置类配置Swagger信息1、编写Swagger配置类配置Swagger扫描接口1、配置扫描的接口2、配置是否启动SwaggerSwagger配置多环境1、新建application-dev.properties新建a. 阅读详情

相关推荐

无聊的时候怎么办?教你用java写一个简单挂机打金币小游戏吧!

无聊的时候怎么办?教你用java写一个超简单挂机打金币小游戏吧!Java写一个挂机打金币程序1.Java的面向对象2.基础打金的分析3. Robot介绍以及Demo演示4.挂机打金程序如何去实现 Java写一个挂机打金币程序 [图片上传失败…(image-529a95-1627970545922)] 1.Java的面向对象 就是万事万物皆对象; 2.基础打金的分析 初级: 我们去模拟人类的按键和鼠标点击 ; 完成刷金币的一个行为; 按键精灵 3. Robot介绍以及Demo演示 4.挂机打金程序如.

Delilah_java的博客 800

字节技术官手码1938页LeetCode热门高解,GitHub已上榜

一直以来,刷力扣都是程序员学习算法路上最大的绊脚石,但是究竟应该怎么刷呢,相信还是有很多人不知道。掌握方法很重要,正所谓“做好准备,事半功倍”,所以正确的方法尤为重要。假如你在LeetCode刷题发现看懂了但是却写不出来,不要担心,这是十分正常的事情,前段时间刚刷过的题,再用的时候也不会,这也是正常的今天小编就给大家分享一下我的“经验”以及我的刷题资料,希望能帮到大家。

Trouvailless的博客 382

AI应用架构师:引领半导体良率AI预测的变革浪潮

在半导体行业这个技术密集、资本密集且竞争异常激烈的领域,良率是决定企业盈利能力的关键指标。每提升1%的良率可能意味着数亿美元的利润增长。然而,随着制程节点不断缩小至3nm、2nm甚至更先进水平,传统的良率管理方法已难以应对日益复杂的制造流程和指数级增长的数据量。本文将深入探讨AI应用架构师如何成为这场变革的核心驱动力,通过设计和实施先进的AI预测系统,将半导体良率预测从传统的"事后分析"转变为"事前预测"和"实时优化"。

AI大模型应用之禅 403

在GitHub已上榜,字节技术官手码1938页LeetCode热门高解

掌握方法很重要,正所谓“做好准备,事半功倍”,所以正确的方法尤为重要。假如你在LeetCode刷题发现看懂了但是却写不出来,不要担心,这是十分正常的事情,前段时间刚刷过的题,再用的时候也不会,这也是正常的今天小编就给大家分享一下我的“经验”以及我的刷题资料,希望能帮到大家。如果你是为了找工作而“临阵磨枪”,小编的建议是直接观看这份《LeetCode热门高解》,也就几千道题吧,吃透一半,offer还不是手到擒来!!!

m0_73408074的博客 396

在CoppeliaSim里实现一个最简单的强化学习

前言 上一篇文章中介绍了CoppeliaSim的一些基本知识和一个简单的用python去控制CoppeliaSim里面四旋翼无人机运动的一个例子。文章链接 :https://blog.youkuaiyun.com/qq_37051669/article/details/115324851 本文将继续介绍如何利用CoppeliaSim的物理环境去实现一个最简单的强化学习。 如何实现强化学习 强化学习(Reinforcementlearning)是机器学习中的一个领域,强调如何基于环境而行动,以取得最大化的预期利.

qq_37051669的博客 3765

江科大51单片机笔记【1】单片机及开发板介绍

单片机,Micro Controller Unit,简称MCU,内部集成了CPU、RAM、ROM、定时器、中断系统、通讯接口等一系列电脑的常用硬件功能单片机的任务是信息采集(传感器)、处理(CPU)和硬件设备(电机、LED)的控制单片机算是一个袖珍版计算机,是一个完整的计算机系统,成本低体积小结构简单单片机的使用领域:智能仪表、实时工控、通讯设备、导航系统、家用电器等。

2301_80195807的博客 848

跨年巨作!字节技术官手码1938页LeetCode热门高解,GitHub已上榜

如果你是为了找工作而“临阵磨枪”,小编的建议是直接观看这份《LeetCode热门高解》,也就几千道题吧,吃透一半,offer还不是手到擒来!假如你在LeetCode刷题发现看懂了但是却写不出来,不要担心,这是十分正常的事情,前段时间刚刷过的题,再用的时候也不会,这也是正常的。一直以来,刷力扣都是程序员学习算法路上最大的绊脚石,但是究竟应该怎么刷呢,相信还是有很多人不知道。掌握方法很重要,正所谓“做好准备,事半功倍”,所以正确的方法尤为重要。目录也就这点,内容怎么样,你们说了算,反正我已经给你们备好了。

m0_63437643的博客 180

(完整版)从零开始教你玩转ComfyUI-保姆级部署教程-手把手带你ComfyUI工作流搭建

ComfyUI就像拥有一支神奇魔杖,可以轻松创造出令人惊叹的AI生成艺术。从本质上讲,ComfyUI是构建在Stable Diffusion之上的基于节点的图形用户界面(GUI),而Stable Diffusion是一种最先进的深度学习模型,可以根据文本描述生成图像。但ComfyUI真正特别之处在于,它如何让像你这样的艺术家释放创造力,将你最疯狂的想法变为现实。想象一下有一块数字画布,你可以通过连接不同的节点来构建自己独特的图像生成工作流,每个节点代表一个特定的功能或操作。

php源码 4万+

跨年巨作。字节技术官手码1938页LeetCode热门高解,GitHub已上榜

春招已经开始筹备了。你是不是已经开始准备了呢? 一直以来,刷力扣都是程序员学习算法路上最大的绊脚石,但是究竟应该怎么刷呢,相信还是有很多人不知道。 掌握方法很重要,正所谓“做好准备,事半功倍”,所以正确的方法尤为重要。 假如你在LeetCode刷题发现看懂了但是却写不出来,不要担心,这是十分正常的事情,前段时间刚刷过的题,再用的时候也不会,这也是正常的 今天小编就给大家分享一下我的“经验”以及我的刷题资料,希望能帮到大家。如果你是为了找工作而“临阵磨枪”,小编的建议是直接观看这份《Lee.

代码界的扛把子 246

热力学仿真软件:Fluent_(8).材料属性设置

在 Fluent 中,材料属性主要包括密度、比热容、导热系数、黏度等物理性质。这些属性在不同的仿真场景中有着不同的作用,例如在流体仿真中,密度和黏度是必不可少的;在传热仿真中,导热系数和比热容是主要考虑的因素。如果所需的材料不在材料库中,或者需要对现有材料进行修改,用户可以自定义材料属性。在主菜单中选择Materials。点击打开材料编辑器。在材料编辑器中,点击Create按钮,输入新的材料名称。选择材料类型(如FluidSolid等)。在属性栏中填写所需的材料属性。

kkchenjj的博客 1495

YOLOv11改进 | 引入SFSConv空间频率选择卷积(含SFSC3k2二次创新),空间频率特征协同作用,检测性能全面提升

本文提出在YOLOv11中引入SFSConv空间频率选择卷积模块,通过显式分离和动态融合空间域与频率域特征,解决传统卷积对多尺度目标检测的局限性。SFSConv包含空间频率分离、动态权重融合和协同特征重建三个核心机制,并进一步创新提出SFSC3k2结构,通过双路频率分支增强特征协同作用。该改进显著提升了YOLOv11在遥感、医学等多尺度复杂场景下的检测性能,实验显示在微小目标检测任务中mAP提升5%-10%。代码实现展示了SFSConv模块的核心逻辑及其在PyTorch中的高效实现。

走向CTO的路上... 769

一篇JVM详细图解,坚持看完!带你真正搞懂Java虚拟机!

一篇JVM详细图解,坚持看完!带你真正搞懂Java虚拟机!Java虚拟机1、JVM简介2、JVM内存区域2.1、程序计数器(线程私有)2.2、虚拟机栈(线程私有)2.3、本地方法区(线程私有)2.4、堆(Heap-线程共享)2.5、方法区/永久代(线程共享)3、JVM类加载器4、双亲委派机制5、沙箱安全机制6、GC垃圾回收算法6.1、如何确定垃圾6.2、标记清除算法(Mark-Sweep)6.3、复制算法(copying)6.4、标记整理算法(Mark-Compact)6.5、分代收集算法 Java虚拟机.

Delilah_java的博客 1万+

Android 14.0 SystemUI状态栏居中显示时间和修改时间显示样式

在14.0的系统rom定制化开发中,在systemui状态栏系统时间默认显示在左边和通知显示在一起,但是客户想修改显示位置,想显示在中间,所以就要修改SystemUI 的Clock.java 文件这个就是管理显示时间的,居中显示的话就得修改布局文件了

安卓兼职framework和app工程师的博客 980

什么?学java这么久了,你对“SpringMVC-JSON“真的了解吗?

什么?学java这么久了,你对"SpringMVC-JSON"真的了解吗?SpringMVC--JSON1、JSON简介2、JavaScript中使用JSON3、Jackson4、Jackson日期工具类5、FastJson SpringMVC–JSON 1、JSON简介 什么是 JSON JSON(JavaScript Object Notation,JS 对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。 采用完全独立于编程语言的文本格式来存储和表示数据。 简洁和清晰的层次结构使得 JSO.

Delilah_java的博客 2202

【DaVinci Developer专题】-36-创建一个“既读又写”的Sender Receiver Port(SR PR-Port)

有时会遇到SWC需要对一个Port进行“既可以读,也可以写”的操作。以下图为例,Test_A_SWC中Test_A_Port是P-Port;Test_B_SWC中Test_A_Port是R-Port。Test_C_SWC需要对Test_A_Port同时进行“读”和“写”。 该篇将详细介绍PR-Port的创建方法。 目录 1 创建一个S/R Port Interface 2 将一个PR-Port端口添加至Application Component 3 PR-Port端口初始化 4 Run.

「汽车电子助手」的博客 3014

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

字节架构师:来说说Java异步调用的几种方式你都搞懂了吗?

字节架构师:来说说Java异步调用的几种方式你都搞懂了吗?一、通过创建新线程二、通过线程池三、通过@Async注解四、通过CompletableFuture 日常开发中,会经常遇到说,前台调服务,然后触发一个比较耗时的异步服务,且不用等异步任务的处理结果就对原服务进行返回。这里就涉及的Java异步调用的一个知识。下面本文尝试将Java异步调用的多种方式进行归纳。 一、通过创建新线程 首先的我们得认识到,**异步调用的本质,其实是通过开启一个新的线程来执行。**如以下例子: public static.

Delilah_java的博客 2082

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

零基础学java,其实没有那么难!先从java基础之Object类开始吧!

零基础学java,其实没有那么难!先从java基础之Object类开始吧!java基础之Object类2、代码演示2.1、Demo12.2、Demo23、克隆方法 java基础之Object类 Object类是是所有类的父类,对于java中的任意一个类来说,都是Object类的子类。 Object类中的源码: public class Object { // 本地注册一些必要信息 private static native void registerNatives(); st.

Delilah_java的博客 1593

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

关于什么是Maven“依赖传递”、“依赖冲突”,Java程序员有话说!

关于什么是Maven“依赖传递”、“依赖冲突”,Java程序员有话说!什么是依赖传递?什么是依赖冲突?如何解决依赖冲突1. 使用maven提供的依赖调解原则2.排除依赖3.锁定版本 什么是依赖传递? 在maven中,依赖是可以传递的,假设存在三个项目,分别是项目A,项目B以及项目C,假设C依赖B,B依赖A,那么我们可以根据maven项目依赖的特征不难推出项目C也依赖A。 什么是依赖冲突? 大家都要用到一个工具包,由于依赖传递大家都会导入,发现大家导入的工具包版本不统一,就产生了冲突 eg: spring.

Delilah_java的博客 1401

为什么越来越多程序员使用Netty编程框架,这些原因你都知道吗?

为什么越来越多程序员使用Netty框架,这些原因你都知道吗?一、传统的BIO编程二、伪异步的I/O编程三、NIO编程四、AIO编程五、I/O模型对比六、主流NIO框架七、为什么学习Netty7.1 不选择Java原生NIO的原因7.2 选择Netty的理由八、Netty开发环境搭建8.1 Netty 的官网8.2 Maven仓库地址8.3 Maven依赖8.4 Gradle依赖 一、传统的BIO编程 ​ 网络编程的基本模型是Client/Server 模型,也就是两个进程之间进行相互通信,其中服务端提供位.

Delilah_java的博客 1345

面试被问到如何用Springboot 进行 web开发,看完这篇!怒怼面试官!

面试被问到如何用Springboot 进行 web开发,看完这篇!怒怼面试官!web开发静态资源首页一、在静态资源目录下新建index.html二、编写controller层三、运行测试 web开发 静态资源 四个目录存放的静态资源可以被我们识别,用来存放我们的html、css、js、图片等文件 "classpath:/META-INF/resources/" "classpath:/resources/" "classpath:/static/" "classpath:/public/" 他们的.

Delilah_java的博客 915

Java程序员都会碰到的Mysql索引失效问题,看完收获满满!

Java程序员都会碰到的Mysql失效问题,看完收获满满!准备Explain关键字索引普通索引唯一索引使用ALTER 命令添加和删除索引使用ALTER 命令添加和删除主键索引失效违反最左前缀法则在索引列上操作范围索引右边的列失效使用不等于like以通配符开头("%abc")字符串不加单引号使用or连接order bygroup by 准备 为了进行Mysql失效的实践,我们首先创建一个表,执行以下 sql 语句: mysql> create table staff( -> id int.

Delilah_java的博客 732

面试被问java线程状态,一脸茫然?莫慌!看完这篇 从容应对!

面试被问java线程状态,一脸茫然?莫慌!看完这篇 从容应对!Java的线程状态线程方法停止线程线程休眠线程礼让线程强制执行线程状态观测线程的优先级守护(deamon)线程 Java的线程状态 线程方法 方法 说明 setPriority(int newPriority) 更改线程的优先级 static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠 void join() 等待该线程终止 static void yield() 暂停当.

Delilah_java的博客 712
上一篇: 创建Java线程原来这么简单?!通俗易懂!阿里工程师用实例教你创建Java线程
下一篇: 程序员面试再不了解JVM? 你就OUT了!一篇教你秒懂Java垃圾回收机!
Danny_java
博客等级 码龄5年 9粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值