- 相交链表
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null && headB == null) return null;
ListNode pa = headA,pb = headB;
while(pa != pb){
pa = pa == null ? headB: pa.next;
pb = pb == null ? headA: pb.next;
}
return pb;
}
- 删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。
现有一个链表 – head = [4,5,1,9],它可以表示为:
示例 1:
输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入:head = [4,5,1,9], node = 1
输出:[4,5,9]
解释:给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
- 链表的中间结点
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
思路
public ListNode middleNode(ListNode head) {
int length = len(head);
int mid = length/2;
int i =0;
if(head.next != null){
i++;
if(i == mid){
return head;
}
head = head.next;
}
return head.next;
}
public int len(ListNode head){
int length =0;
if(head.next != null){
length++;
head = head.next;
}
return length;
}
快慢指针
public ListNode middleNode(ListNode head) {
ListNode slow = head,fast= head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
- 二进制链表转整数
给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。
请你返回该链表所表示数字的 十进制值 。
示例 1:
输入:head = [1,0,1]
输出:5
解释:二进制数 (101) 转化为十进制数 (5)
思路
public int getDecimalValue(ListNode head) {
int count =0;
int len = len(head);
while(head.next != null){
for(int i= len;i>= 0;i--){
count += head.val*Math.pow(2,i);
}
head = head.next;
}
return count;
}
public int len(ListNode head){
int length =0;
if(head.next != null){
length++;
head = head.next;
}
return length;
}
public int getDecimalValue(ListNode head) {
int ans =0;
while(head != null){
ans = ans*2 + head.val;
head = head.next;
}
return ans;
}
剑指 Offer 06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public int[] reversePrint(ListNode head) {
Stack<Integer> stack = new Stack<Integer>();
ListNode res = head;
while(res != null){
stack.push(res.val);
res = res.next;
}
int size = stack.size();
int[] cur = new int[size];
for(int i =0;i < size; i++){
cur[i] = stack.pop();
}
return cur;
}
剑指 Offer 18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
思路
public ListNode deleteNode(ListNode head, int val) {
if(head == null) return null;
ListNode res = head,pre = null;
while(res != null){
if(res.val == val && res.next != null){
pre.next = res.next;
} else{
res.next = null;
}
pre = res;
res = res.next;
}
return res;
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public ListNode deleteNode(ListNode head, int val) {
if(head == null) return head;
if(head.val == val) return head.next;
ListNode pre = head,res = head.next;
while(res != null && res.val != val){
pre = res;
res = res.next;
}
pre.next = (res== null) ? null : res.next;
return head;
}
剑指 Offer 22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
思路
public ListNode getKthFromEnd(ListNode head, int k) {
Queue<ListNode> queue = new LinkedList<>();
ListNode res = null;
queue.offer(head);
int size = queue.size();
for(int i =size; i>size - k ;i--){
res= queue.poll();
}
return res;
}
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode pre = head,res = head;
for(int i=0; i<k; i++){
res = res.next;
}
while(res != null){
pre = pre.next;
res = res.next;
}
return pre;
}
剑指 Offer 24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
思路
public ListNode reverseList(ListNode head) {
Stack<ListNode> stack = new Stack<>();
while(head != null){
stack.push(head);
head = head.next;
}
ListNode res = null;
for(int i =0; i< stack.size();i++){
res = stack.pop();
}
return res;
}
public ListNode reverseList(ListNode head) {
if(head == null) return null;
ListNode pre = null,res = head;
while(res!= null){
ListNode next = res.next;
res.next = pre;
pre = res;
res = next;
}
return pre;
}
面试题 02.01. 移除重复节点
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例1:
输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]
示例2:
输入:[1, 1, 1, 1, 2]
输出:[1, 2]
class Solution {
public ListNode removeDuplicateNodes(ListNode head) {
if (head == null) {
return head;
}
Set<Integer> occurred = new HashSet<Integer>();
occurred.add(head.val);
ListNode pos = head;
// 枚举前驱节点
while (pos.next != null) {
// 当前待删除节点
ListNode cur = pos.next;
if (occurred.add(cur.val)) {
pos = pos.next;
} else {
pos.next = pos.next.next;
}
}
pos.next = null;
return head;
}
}
public ListNode removeDuplicateNodes(ListNode head) {
if(head == null) return null;
Set<Integer> set = new HashSet<>();
set.add(head.val);
ListNode pre = head;
while (pre.next != null) {
ListNode cur = pre.next;
if(set.add(cur.val)){
pre = pre.next;
}else{
pre.next = pre.next.next;
}
}
pre.next = null;
return head;
}
面试题 02.06. 回文链表
编写一个函数,检查输入的链表是否是回文的。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
public boolean isPalindrome(ListNode head) {
if(head == null) return true;
ListNode first = endofList(head);
ListNode sencond = reverseList(first.next);
boolean result= true;
ListNode p1 = head;
ListNode p2 = sencond;
while(result && p2 != null){
if(p1.val != p2.val){
result = false;
}
p1 = p1.next;
p2 = p2.next;
}
return result;
}
public ListNode reverseList(ListNode head){
ListNode pre = null,res = head;
while(res != null){
ListNode next = res.next;
res.next = pre;
pre = res;
res = next;
}
return pre;
}
public ListNode endofList(ListNode head){
ListNode solw = head,fast = head;
while(fast.next != null && fast.next.next != null){
solw = solw.next;
fast = fast.next.next;
}
return solw;
}