/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode pre = dummyHead;
while (pre.next != null) {
if(pre.next.val == val) {
pre.next = pre.next.next;
}
else {
pre = pre.next;
}
}
return dummyHead.next;
}
}
思路图解:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null) {
return head;
}
ListNode res = removeElements(head.next, val);
if(head.val == val) {
return res;
}else {
head.next = res;
return head;
}
}
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
/**
* 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
* 如果有两个中间结点,则返回第二个中间结点。
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast = head;
ListNode low = head;
while(fast.next!=null) {
if(fast.next.next != null) {
//不这样写会产生nullpointer错误
fast = fast.next.next;
low = low.next;
}else {
fast = fast.next;
low = low.next;
}
}
return low;
}
}
思路:创建一个新的链表,用头插法来放入数据达到反转目的;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
//创建新链表头节点,该新链表是由原链表头插发新创建的
ListNode dummyHead = new ListNode(-1);
ListNode temp = new ListNode(-1);
for (temp.next = head;temp.next != null; temp = temp.next) {
ListNode newNode = new ListNode(temp.next.val);
//头插法
newNode.next = dummyHead.next;
dummyHead.next = newNode;
}
return dummyHead.next;
}
}
思路:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = new ListNode(-1);
pre.next = head;
if (head == null || head.next ==null) {
//判断头节点是否为空或只有一个节点
return head;
}else {
ListNode q = head;
ListNode h = q.next;
while(h != null) {
q.next = h.next;
h.next = pre.next; //这几条语句顺序不能乱
pre.next = h;
h = q.next;
}
return pre.next;
}
}
}
思路:要判断一个单链表是否为回文链表:
/**
* @Author : YangY
* @Description : 对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
* 给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
* 测试样例:
* 1->2->2->1
* 返回:true
* @Time : Created in 15:27 2019/3/3
*/
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x; }
}
public class Solution {
public boolean chkPalindrome(ListNode A) {
// write code here
if (A == null || A.next == null) {
return true;
}
//寻找中间节点,若为偶数则返回两个中间节点后面那一个;
ListNode fast = A;
ListNode slow = A;
while (fast.next != null) {
if(fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}else {
fast = fast.next;
slow = slow.next;
}
}
ListNode mid = slow;
//反转后半部分
ListNode dummyHead = new ListNode(-1);
dummyHead.next = mid;
ListNode q = mid;
ListNode h = mid.next;
while (h != null) {
q.next = h.next;
h.next = dummyHead.next;
dummyHead.next = h;
h = q.next;
}
//比较翻转后的链表与前半部分链表
while (A.next != null && dummyHead.next != null) {
if (A.val != dummyHead.next.val) {
return false;
} else {
A = A.next;
dummyHead.next = dummyHead.next.next;
}
}
return true;
}
}
/**
* @Author : YangY
* @Description : 递归计算数组内所有元素的和
* @Time : Created in 19:22 2019/3/5
*/
public class Test {
public static void main(String[] args) {
int[] arr = new int[]{
1,3,4,5};
System.out.println(sum(0,arr));
}
public static int sum(int l, int[] array) {
if (l == array.length) {
return 0;
}else {
return array[l] + sum(l+1, array);
}
}
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
int count = 0;
ListNode dummyHeadL1 = new ListNode(-1);
ListNode dummyHeadL2 = new ListNode(-1);
dummyHeadL1.next = l1;
dummyHeadL2.next = l2;
ListNode dummyHeadNew = new ListNode(-1);
ListNode dummyHeadCopy = dummyHeadNew;
//若两个都为空
if (l1==null && l2== null) {
return l1;
}
//比较到最后一定会只剩下一个不为空
while(dummyHeadL1.next != null || dummyHeadL2.next != null) {
if (dummyHeadL1.next == null || dummyHeadL2.next == null) {
if (dummyHeadL1.next == null) {
dummyHeadNew.next = dummyHeadL2.next;
dummyHeadL2 = dummyHeadL2.next;
}else {
dummyHeadNew.next = dummyHeadL1.next;
dummyHeadL1 = dummyHeadL1.next;
}
}else {
if (dummyHeadL1.next.val <= dummyHeadL2.next.val) {
dummyHeadNew.next = dummyHeadL1.next;
dummyHeadL1.next = dummyHeadL1.next.next;
}else {
dummyHeadNew.next = dummyHeadL2.next;
dummyHeadL2.next = dummyHeadL2.next.next;
}
}
count++;
if(count == 1) {
dummyHeadCopy = dummyHeadNew.next;
}
dummyHeadNew = dummyHeadNew.next;
}
return dummyHeadCopy;
}
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// 类似归并排序中的合并过程
ListNode dummyHead = new ListNode(0);
ListNode cur = dummyHead;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
cur.next = l1;
cur = cur.next;
l1 = l1.next;
} else {
cur.next = l2;
cur = cur.next;
l2 = l2.next;
}
}
// 任一为空,直接连接另一条链表
if (l1 == null) {
cur.next = l2;
} else {
cur.next = l1;
}
return dummyHead.next;
}
}
开始我很疑惑,dummyHead始终都没有初始化,怎么会得出结果,其实ListNode cur = dummyHead这条语句为引用传递,此处并没有new关键字,所以它两指向同一块空间。
这种问题用快慢指针法,十分简单
规律:快指针先走n-1步,然后快慢指针一起走,当快指针走到最后时,慢指针则为倒数n节点;
代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode FoundNthFromEnd(ListNode head, int n) {
ListNode fast = head;
while(n-1 > 0) {
fast = fast.next;
n--;
}
ListNode slow = head;
while(fast.next != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
这个问题是第7个问题的升级版
思路:可容易发现,我们可以用快慢指针找到被删节点的前一节点,由于是删除节点,所以要找的是前一节点,与上面的寻找倒数n节点只有一点差异;规律:先让快指针走n步,在让快慢指针一起走,当快指针为空时,慢指针则是倒数n节点的上一节点 ;
坑点:要删除的节点为首节点时,我们要按另一种方法来算;(只有当删除头节点时,first节点移动n步后一定为空,其他情况绝对不会为空,凭这一点可找出删除头节点的情况)代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//快指针提前先走n步
ListNode fast = head;
while(n > 0){
fast = fast.next;
n--;
}
//如果此时快指针已经为空了,说明待删除的是头节点,直接返回结果
if(fast == null) return head.next;
ListNode slow = head;
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
//此时slow指向的是待删除节点的前一个前点
slow.next = slow.next.next;
return head;
}
}
题目描述:
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
解题思路:
该问题适合用递归来解决,我们将第k个节点作为参数进行递归,每个函数返回翻转后的头节点,这个头节点作为上一个递归的尾节点,有了尾节点和头节点,在函数体内就可以执行翻转;
代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode current_node = head;
int count = 0;
while(count < k && current_node != null) {
current_node = current_node.next;
count++;
}
//判断是否够分k个
if(count == k) {
current_node = reverseKGroup(current_node,k);
while(count > 0) {
ListNode h = head.next;
head.next = current_node;
current_node = head;
head = h;
count--;
}
//走完这个循环,current_node代表当前链表的头;
head = current_node;
}
return head;
}
}
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
解答:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) {
return head;
}else {
ListNode res = swapPairs(head.next.next);
ListNode temp = head.next;
temp.next = head;
head.next = res;
return temp;
}
}
}
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
发现规律:若右移k个,则只需将倒数k个节点搬移到head的前面即可;
解题:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null) {
return head;
}
ListNode temp = head;
int count = 0;
while(temp.next!=null) {
temp = temp.next;
count++; //这里的count是总节点数减一哟
}
int i = 0;
ListNode newNode = null;
if (k%(count+1)==0) {
//如果为链表总长度的整数倍,则不需要移动
return head;
}else {
ListNode last = head;
int num =count - k%(count+1);
for(;i < num;i++) {
last = last.next;
}
temp.next = head;
newNode = last.next;
last.next = null;
}
return newNode;
}
}