import java.util.*;
/**
* @xxx
* @create2020-09-13 15:20
*/
public class Solution {
/**
* 输入一个链表,反转链表后,输出新链表的表头。
*
* @param head 头结点
* @return 头结点
*/
public static ListNode ReverseList(ListNode head) {
if (head == null)
return null;
ListNode pre = null;
ListNode next;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
/**
* 递归方法
*
* @param head
* @return
*/
public static ListNode ReverseList2(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode next = head.next;
ListNode newHead = ReverseList2(next);
next.next = head;
head.next = null;
return newHead;
}
/**
* 链表中的节点每k个一组翻转
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null || head.next == null || k < 2) return head;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy, cur = head, temp;
int len = 0;
while (head != null) {
len++;
head = head.next;
}
for (int i = 0; i < len / k; i++) {
for (int j = 1; j < k; j++) {
temp = cur.next;
cur.next = temp.next;
temp.next = pre.next;
pre.next = temp;
}
pre = cur;
cur = cur.next;
}
return dummy.next;
}
/**
* 判断给定的链表中是否有环
*
* @param head
* @return
*/
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
if (head.next != null && head.next.next == null) {
return false;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null && slow != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
return false;
}
/**
* 找出两个链表的第一个公共结点
*
* @param pHead1
* @param pHead2
* @return
*/
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode l1 = pHead1, l2 = pHead2;
while (l1 != l2) {
l1 = (l1 == null) ? pHead2 : l1.next;
l2 = (l2 == null) ? pHead1 : l2.next;
}
return l1;
}
/**
* 归并两个有序的链表
*
* @param l1
* @param l2
* @return
*/
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
/**
* 合并k个已排序的链表
*
* @param lists
* @return
*/
public ListNode mergeKLists(ArrayList<ListNode> lists) {
if (lists == null || lists.size() == 0) {
return null;
}
return mergeList(lists, 0, lists.size() - 1);
}
private ListNode mergeList(ArrayList<ListNode> lists, int low, int height) {
if (height <= low) return lists.get(low);
int mid = low + ((height - low) >> 1);
ListNode left = mergeList(lists, low, mid);
ListNode right = mergeList(lists, mid + 1, height);
return mergeList(left, right);
}
/**
* 归并两个有序的链表
*
* @param l1
* @param l2
* @return
*/
private ListNode mergeList(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val < l2.val) {
l1.next = mergeList(l1.next, l2);
return l1;
} else {
l2.next = mergeList(l1, l2.next);
return l2;
}
}
public ListNode addTwoNumbers(ListNode head1, ListNode head2) {
Stack<Integer> l1Stack = buildStack(head1);
Stack<Integer> l2Stack = buildStack(head2);
ListNode head = new ListNode(-1);
int carry = 0;
while (!l1Stack.isEmpty() || !l2Stack.isEmpty() || carry != 0) {
int x = l1Stack.isEmpty() ? 0 : l1Stack.pop();
int y = l2Stack.isEmpty() ? 0 : l2Stack.pop();
int sum = x + y + carry;
ListNode node = new ListNode(sum % 10);
node.next = head.next;
head.next = node;
carry = sum / 10;
}
return head.next;
}
private Stack<Integer> buildStack(ListNode l) {
Stack<Integer> stack = new Stack<>();
while (l != null) {
stack.push(l.val);
l = l.next;
}
return stack;
}
/**
* 给定一个链表,请判断该链表是否为回文结构。
*
* @param head ListNode类 the head
* @return bool布尔型
*/
public boolean isPail(ListNode head) {
ArrayList<Integer> list = new ArrayList<>();
ListNode cur = head;
while (cur != null) {
list.add(cur.val);
cur = cur.next;
}
int l = 0, r = list.size() - 1;
while (l < r) {
if (!list.get(l).equals(list.get(r))) {
return false;
} else {
l++;
r--;
}
}
return true;
}
/**
* 链表中环的入口节点
*
* @param head
* @return
*/
public ListNode detectCycle(ListNode head) {
if (head == null) return head;
ListNode slow = head;
ListNode fast = head;
ListNode meet = null;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (fast == slow) {
meet = fast;
break;
}
}
if (meet == null) return null;
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
/**
* 链表内指定区间反转
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
public ListNode reverseBetween(ListNode head, int m, int n) {
if (head == null) return null;
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy;
for (int i = 0; i < m - 1; ++i) {
pre = pre.next;
}
ListNode cur = pre.next;
ListNode next = cur.next;
for (int i = 0; i < n - m; i++) {
cur.next = next.next;
next.next = pre.next;
pre.next = next;
next = cur.next;
}
return dummy.next;
}
/**
* 链表中倒数第k个结点
*
* @param head
* @param k
* @return
*/
public ListNode FindKthToTail(ListNode head, int k) {
ListNode p, q;
for (p = q = head; p != null; p = p.next, k--)
if (k <= 0)
q = q.next;
return k <= 0 ? q : null;
}
/**
* 删除链表的倒数第n个节点
*
* @param head ListNode类
* @param n int整型
* @return ListNode类
*/
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode first = head;
ListNode second = head;
for (int i = 0; i < n; i++)
first = first.next;
//如果n的值等于链表的长度,直接返回去掉头结点的链表
if (first == null)
return head.next;
while (first.next != null) { //同时移动两个指针
first = first.next;
second = second.next;
}
second.next = second.next.next;
return head;
}
/**
* 删除有序链表中重复的元素
*
* @param head
* @return
*/
public ListNode deleteDuplicates1(ListNode head) {
if (head == null || head.next == null) return head;
head.next = deleteDuplicates1(head.next);
return head.val == head.next.val ? head.next : head;
}
/**
* 删除有序链表中重复出现的元素
*
* @param head
* @return
*/
public ListNode deleteDuplicates2(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode newHead = new ListNode(head.val - 1);
newHead.next = head;
ListNode cur = head;
ListNode last = newHead;
while (cur != null && cur.next != null) {
if (cur.val != cur.next.val) {
last = cur;
} else {
while (cur.next != null && cur.val == cur.next.val)
cur = cur.next;
last.next = cur.next;
}
cur = cur.next;
}
return newHead.next;
}
}
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
相关推荐
2025字节测试面试全攻略:高频考点与实战应对思路
软件测试从功能验证走向全栈质量保障,字节跳动等大厂对测试工程师的要求已覆盖用例设计、接口自动化、性能排查与算法手撕。理解HTTP协议、pytest框架、Linux命令等底层原理,是构建自动化测试体系与高效排查线上问题的基础。从等价类、边界值等经典方法到缓存穿透、弱网模拟等实战场景,测试人员需要将技术能力转化为业务价值。本文围绕2025年字节测试面试高频考点,系统梳理答题框架与避坑思路,助力候选人高效备战。
想去看机会?这10道最高频的手撕代码题都会了吗?
想去看机会?下面这10道最高频的手撕代码面试题都会了吗?相信我,彻底掌握以下这10道题的解法,你顺利做出手撕代码面试题目的概率至少不低于50%。1,快速排序题目形式:手写...
生信实战|EffectorP3.0在植物病原菌效应子预测中的高效应用
本文详细介绍了EffectorP 3.0在植物病原菌效应子预测中的高效应用。通过机器学习模型,该工具能快速从海量分泌蛋白中批量预测胞质与质外体效应子,显著提升研究效率。文章提供了从环境配置、RNA-seq数据处理到批量预测的完整实战流程,并分享了结果解读与避坑指南,是生信研究人员进行病原物效应子鉴定的必备利器。
手撕最常见的算法岗面试题(25道)
手撕最常见的算法岗面试题(20道)
手撕代码系列:Conv2D
在实际的神经网络中,每个卷积核都会对应一个偏置值。这意味着如果网络有多个卷积核,每个卷积核的输出都可以加上对应的偏置。
YOLOv11 改进策略 | HWD:引入 Haar 小波变换,减少信息丢失
在卷积神经网络(CNN)中,下采样(Downsampling)是降低特征图分辨率、扩大感受野的关键操作,通常通过最大池化(MaxPool)或步长为 2 的卷积(Strided Convolution)实现。然而,这些方法在降低分辨率的同时,往往会丢失图像中的高频细节信息(如边缘、纹理)和精确的空间位置信息,这可能对后续特征提取和目标检测精度产生不利影响,尤其是对于小目标和需要精细定位的任务。
【数据结构与算法】---OJ手撕链表题
小编带大家学习链表OJ题。
基于Java+Maven+Testng+RestAssured+Allure+Jenkins搭建一个接口自动化框架
2、有一个提取表达式列,通过编写每个接口的JSON提取表达式,后边在解析Excel时,对接口执行后的响应数据用该表达式提取出来,保存到环境变量,如果某些接口需要前置接口的响应数据,我们就可以从环境变量中获取该数据出来,从而解决了接口关联的问题。1、在之前介绍过全局配置类Contants中添加一个控制台日志开关控制权限,如果选择为false,则控制台不输出日志,将日志输出到allure报表,选择为true,则在控制台输出日志,不输出到allure报表。
“手撕“9道经典链表算法题
在学完单链表(单向不带头不循环)和双向链表(双向带头循环)后我们会发现双向链表虽然结构略微复杂,但实现相同功能时相较于单链表方便了不止一星半点。
EBS开发_离散工单创建API
--以下代码于20171213在TONY环境中实现 DECLARE l_iface_rec wip.wip_job_schedule_interface%ROWTYPE; --工单任务接口表 l_group_id NUMBER; l_returnstatus VARCHAR2(40); l_errormsg VARCHAR2(2000
Blender入门教程-3D视图界面介绍
3D视图用于与3D场景交互,可用于各种目的,例如建模、动画、纹理绘制等。在关闭 启动画面 后,启动场景会显示在3D视口中(如果没有加载其他blend文件)。01 标题栏标题栏包含了基于当前 模式 的各种菜单和控制。
弱校本科生算法岗春招实习面经:从手撕代码到机器学习理论全记录
面试算法岗,尤其是春招实习,考察的不仅是算法功底,更是在有限时间内展现工程思维与理论深度。从手撕二分、快排、KMP到二叉树LCA与动态规划,每一道算法题背后都对应着数据结构与复杂度的核心原理。机器学习理论同样关键,XGBoost为何优于GBDT、逻辑回归为何用交叉熵、Transformer为何需要位置编码,这些高频问题本质上都在考察对模型设计动机的深入理解。扎实掌握经典算法与模型原理,能有效提升候选人在推荐系统、自然语言处理等落地场景中的问题分析能力。对于学历背景普通的学生,通过系统刷题、项目复盘和面试沉淀
R语言中5种正态性检验的方法
统计学中的t检验和方差分析等方法的应用条件是样本都来自正态总体或近似正态总体,只有符合这个条件,才能用这些方法来检验各样本所属的总体参数的差异显著性。文本向大家介绍在R语言中检验正态性的几种方法: 1、Kolmogorov-Smirnov检验 K-S检验检验单一样本是否来自某一特定分布。比如检验一组数据是否为正态分布。它的检验方法是以样本数据的累积频数分布与特定理论分布比较,若两者间的差距很小,则推论该样本取自某特定分布族。K-S检验的原假设和备择假设为: H0:样本所来自的总体分布服从
华为Java岗面试通关指南:底层原理与手撕代码实战
Java基础、集合框架、JVM与并发编程是大厂面试的核心考区,也是很多候选人背了答案却扛不住追问的重灾区。真正高效的备考方式,不是死记硬背面试题,而是理解技术底层的设计逻辑——例如HashMap的树化阈值为什么是8、Spring三级缓存如何解决循环依赖、线程池参数如何结合业务场景计算。针对华为通用软件Java岗,面试重点覆盖考点地图、算法手撕、项目深挖与系统设计四个维度,其中ACM模式的代码练习、线上OOM排查思路以及分布式锁等场景化题目尤为关键。本文结合2025年高频趋势,拆解面试官追问链路,帮助求职者从
PX4从放弃到精通(二十八):垂起过渡控制
固件版本:1.14.0可加名片交流学习。
efm32 入门.pdf
本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。
链表高频面试算法题
这是一道经典的链表问题,先看一下题目:输入两个链表,找出它们的第一个公共节点。例如下面的两个链表:两个链表的头结点都是已知的,相交之后成为一个单链表,但是相交的位置未知,并且相交之前的结点数也是未知的,请设计算法找到两个链表的合并点。将常用数据结构和常用算法思想都想一遍,看看哪些能解决问题。常用的数据结构有数组、链表、队、栈、Hash、集合、树、堆。常用的算法思想有查找、排序、双指针、递归、迭代、分治、贪心、回溯和动态规划等等。
lwip-2.0.3
lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。
字节面试实战指南:从算法手撕到系统设计底层考点全解析
位和字节是计算机存储的基础单位,1字节等于8位,而KB、MB、GB按1024换算,这些看似简单的概念在编码、容量估算与网络协议中频频出现。字节序决定多字节整数在内存中的排列方式,大端小端的判断与转换是网络编程和跨平台开发的常见考点;字节对齐则影响结构体内存布局与性能,在底层存储和引擎优化中不可忽视。理解这些底层原理,不仅能精准解决“0字节磁盘空间”等问题,更能帮助开发者设计高效的数据结构与通信协议。从算法手撕、项目深挖到系统设计,面试官常以这些技术点为切入点考察候选人的基本功。本文结合字节系面试实战经验,系
蓝牙模块HM-10手册
蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。
锂电池充电器电路设计 里面有电路
锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。
机器学习算法岗面试全记录:大厂考点拆解与手撕代码复盘
机器学习算法是AI领域工程师面试的核心考察点,覆盖监督学习、无监督学习、数据结构与优化算法等多个维度。理解模型推导、适用场景与局限性是夯实基础的关键,而KMP算法、粒子群算法等扩展内容也常成为区分候选人的差异化考点。扎实的算法功底与工程实践能力,直接关系到特征工程、模型评估、线上部署等真实业务问题的解决效率。在腾讯、阿里、网易等大厂算法岗面试中,面试官不仅会追问逻辑回归、SVM、决策树等经典模型的原理细节,还会通过手撕代码、项目深挖、场景设计等环节全面评估候选人的综合能力。以准备面试为契机,系统梳理算法知识
10万字Java面试笔记:核心考点与手撕代码全解析
Java面试是技术招聘中考察候选人工程能力与理论基础的重要环节。面对海量八股文资料,真正高效的备考方式是建立系统化知识框架,而非零散背诵。从集合框架到JVM内存模型,从并发编程到算法手撕,每个考点都需理解其底层原理与设计动机。例如,HashMap的扩容机制、OOM的排查流程、Lambda表达式与Comparator的组合应用,都是高频面试题背后的核心能力体现。排序算法作为手撕代码的必考项,冒泡排序的优化写法、快速排序的分治思想,不仅考察代码实现,更检验对时间复杂度和稳定性的理解。这些知识最终要落到工程实践场
字节跳动算法面试,这样问“链表”太刁钻了
算法为编程语言的基础 技术面试中,面试官一般会先就你所应聘的岗位进行相关知识的考察,也叫基础知识和业务逻辑面试。只要你回答的不是特别特别差,面试官通常会说:“咱们写个代码吧”,这个时候就开始了算法面试。也就是说,一轮技术面试=基础知识和业务逻辑面试+算法面试。 一次字节跳动面试的感慨 前段时间,我曾面试字节跳动,面试官的一道算法题算是把我给难住了,给大家还原当时的面试场景如下: 面试官:给定单链表的头结点 head,实现一个调整链表的函数,从链表尾部开始,以 K 个结点为一组进行逆序翻转,头部剩余结
华为开发岗面试高频考点与备战指南
技术面试的本质,是考察候选人在真实工程场景中解决问题的能力,而非单纯背诵算法结论。从基础数据结构到操作系统原理,从代码实现到系统设计,面试官往往通过层层追问,检验你对内存管理、并发模型、网络协议等核心知识的理解深度。工程实践能力、逻辑推理能力与沟通表达,共同构成了技术人才评估的关键维度。在备战大厂开发岗时,掌握高频考点背后的通用方法,远比堆砌题目数量更重要。本文围绕华为开发岗面试真题,梳理手撕代码、项目深挖、主管面等环节的考察逻辑,拆解高频题型与应对策略,帮助你以工程思维构建完整的面试知识体系。
嵌入式校招手撕代码高频10题:从C语言指针到环形缓冲区全解析
C语言是嵌入式开发的基石,而指针与内存管理则是工程师必须跨越的核心门槛。从字符串拷贝到链表操作,从位运算到状态机设计,每一次手撕代码都在检验开发者对底层原理和硬件特性的理解深度。本文梳理嵌入式校招面试中最高频的10类编码考核题,涵盖C语言基础、内存操作、位运算、数据结构与综合设计等关键方向,解析面试官出题逻辑与常见失分点,帮助开发者构建从“能写代码”到“写能落地的嵌入式代码”的能力进阶路径。这些题目不仅出现在招聘考核中,更是串口通信、DMA缓冲、按键扫描等真实工程场景的缩影。掌握它们,意味着你离一个合格的嵌
大厂程序员面试全流程复盘:从一面到HR面的通关指南
程序员面试不仅是技术考察,更是对问题解决能力与沟通表达的综合评估。从算法题的边界处理到系统设计的容量估算,每一轮面试都有其特定的筛选逻辑。理解面试官背后的评估维度,能够帮助候选人更有针对性地准备。无论你是初次挑战大厂还是多次受挫,掌握从一面到HR面的完整链路,都能显著提升通过率。本文结合真实踩坑经验,梳理了算法准备节奏、项目深挖技巧、系统设计框架以及HR面薪资谈判要点,为你的面试提供一份可落地的行动指南。
刁钻的链表面试题
算法为编程语言的基础 技术面试中,面试官一般会先就你所应聘的岗位进行相关知识的考察,也叫基础知识和业务逻辑面试。只要你回答的不是特别特别差,面试官通常会说:“咱们写个代码吧”,这个时候就开始了算法面试。也就是说,一轮技术面试=基础知识和业务逻辑面试+算法面试。 一次字节跳动面试的感慨 前段时间,我曾面试字节跳动,面试官的一道算法题算是把我给难住了,给大家还原当时的面试场景如下: 面试官:给定单链表的头结点 head,实现一个调整链表的函数,从链表尾部开始,以 K 个结点为一组进行逆序翻转,头部剩余结
米博科技——小厂java实习面经
equals和==的区别:equals本质是object类的一个方法,平时使用的现成equals基本都是重写过的,没重写过的和==没区别,主要用于对象的对比,==用于基本类型的对比。哈希表的了解,问hashmap的实现:数组链表红黑树,在达到一定条件时链表转换为红黑树——这块说了不少。简历里写了自己写过oa系统的审核部分,问用的什么引擎——没答上来。合并链表——只刷过一遍hot100,思路记着,但是紧张没手撕出来。redis使用场景:只知道缓存存储,消息队列,流量控制。
刷面经的正确姿势:从结构拆解到模拟演练的完整闭环
面经作为大厂技术面试准备的重要资料,常被误解为简单题库。实际上,经过结构化归纳的聚合面经,是一种带权重的高频考点地图,其核心价值在于梳理知识点之间的逻辑关系。理解面经2.0的分类、去重与标注原理,能帮助求职者将零散题目还原为知识树,快速定位知识盲区。无论是校招还是社招,后端、前端或算法岗,合理利用面经都可以反推面试官思维,训练临场表达。从粗扫结构、精读高频题、盲写口述到模拟演练,一套完整的方法论能显著提升面试通过率。围绕这套方法,可以拆解不同考核维度的准备策略,并避开常见误区,形成可复用的操作框架。
379



被折叠的 条评论
为什么被折叠?



