赞
踩
实现一种算法,删除单向链表中间的某个节点(即不是第一个或最后一个节点),假定你只能访问该节点。
输入:单向链表a->b->c->d->e->f中的节点c
结果:不返回任何数据,但该链表变为a->b->d->e->f
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val; //将下一节点的值赋给当前节点
node.next = node.next.next; //当前节点的下一个节点为下下节点,删除当前节点
}
}
时间复杂度:O(1)。
空间复杂度:O(1)。
给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。请你返回该链表所表示数字的 十进制值 。
输入:head = [1,0,1]
输出:5
解释:二进制数 (101) 转化为十进制数 (5)
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public int getDecimalValue(ListNode head) { ListNode cur = head; int ans = 0; while(cur != null){ //链表只有0/1 ans = ans * 2 + cur.val; cur = cur.next; } return ans; } }
时间复杂度:O(N),其中N是链表中的节点个数。
空间复杂度:O(1)。
实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
输入: 1->2->3->4->5 和 k = 2
输出: 4
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public int kthToLast(ListNode head, int k) { if(k <= 0 || head == null){ return 0; } ListNode fast = head; ListNode slow = head; //让快指针先快走K-1步 while(k - 1 > 0){ fast = fast.next; k--; } while(fast != null && fast.next != null){ slow = slow.next; fast = fast.next; } return slow.val; } }
时间复杂度 O(N) :N为链表长度。
空间复杂度 O(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; } * } */ class Solution { public int[] reversePrint(ListNode head) { //使用栈,先进后出原则 Stack<ListNode> stack = new Stack<ListNode>(); ListNode node = head; while(node != null){ stack.push(node); node = node.next; } int size = stack.size(); int[] print = new int[size]; for(int i = 0;i < size;i++){ print[i] = stack.pop().val; } return print; } }
时间复杂度:O(n)正向遍历一遍链表,然后从栈弹出全部节点,等于又反向遍历一遍链表。
空间复杂度:O(n)额外使用一个栈存储链表中的每个节点。
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
输入:[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.
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode middleNode(ListNode head) { ListNode slow = head; ListNode fast = head; while(fast != null && fast.next != null){ slow = slow.next; fast = fast.next.next; } return slow; } }
时间复杂度:O(N)O(N),其中 NN 是给定链表的结点数目。
空间复杂度:O(1)O(1),只需要常数空间存放 slow 和 fast 两个指针。
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode removeDuplicateNodes(ListNode head) { if(head == null){ return head; } //HashSet特点无序不可重复 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; } }
时间复杂度:O(N),其中 N 是给定链表中节点的数目。
空间复杂度:O(N)。在最坏情况下,给定链表中每个节点都不相同,哈希表中需要存储所有的 N 个值。
反转一个单链表。
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
/** * 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 prev = null; ListNode curr = head; while(curr != null){ ListNode nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; } }
时间复杂度:O(n),假设 n 是列表的长度,时间复杂度是 O(n)。
空间复杂度:O(1)。
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
/** * 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 mergeTwoLists(ListNode l1, ListNode l2) { ListNode prehead = new ListNode(-1); ListNode prev = prehead; while(l1 != null && l2 != null){ if(l1.val <= l2.val){ prev.next = l1; l1 = l1.next; }else{ prev.next = l2; l2 = l2.next; } prev = prev.next; } //合并后l1和l2最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可 prev.next = l1 == null ? l2 : l1; return prehead.next; } }
时间复杂度:O(n + m)O(n+m) ,其中 nn 和 mm 分别为两个链表的长度。因为每次循环迭代中,l1 和 l2 只有一个元素会被放进合并链表中, 因此 while 循环的次数不会超过两个链表的长度之和。所有其他操作的时间复杂度都是常数级别的,因此总的时间复杂度为 O(n+m)O(n+m)。
空间复杂度:O(1)O(1) 。我们只需要常数的空间存放若干变量。
给定两个(单向)链表,判定它们是否相交并返回交点。请注意相交的定义基于节点的引用,而不是基于节点的值。换句话说,如果一个链表的第k个节点与另一个链表的第j个节点是同一节点(引用完全相同),则这两个链表相交。
输入: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 个节点。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode t1 = headA; ListNode t2 = headB; while(t1 != t2){ t1 = t1 != null ? t1.next : headB; t2 = t2 != null ? t2.next : headA; } return t2; } }
给出一个以头节点 head 作为第一个节点的链表。链表中的节点分别编号为:node_1, node_2, node_3, … 。
每个节点都可能有下一个更大值(next larger value):对于 node_i,如果其 next_larger(node_i) 是 node_j.val,那么就有 j > i 且 node_j.val > node_i.val,而 j 是可能的选项中最小的那个。如果不存在这样的 j,那么下一个更大值为 0 。
返回整数答案数组 answer,其中 answer[i] = next_larger(node_{i+1}) 。
注意:在下面的示例中,诸如 [2,1,5] 这样的输入(不是输出)是链表的序列化表示,其头节点的值为 2,第二个节点值为 1,第三个节点值为 5 。
输入:[2,1,5]
输出:[5,5,0]
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public int[] nextLargerNodes(ListNode head) { int[] arr = new int[10000]; //给定列表的长度在 [0, 10000] 范围内 int[] valueArr = new int[10000]; //给定列表的长度在 [0, 10000] 范围内 Stack<Integer> stack = new Stack<>(); int length = 0; int value; while(head != null){ value = head.val; valueArr[length] = value; while(!stack.isEmpty() && value > valueArr[stack.peek()]){ //栈不为空,且当前值大于前几位 arr[stack.pop()] = value; //将大值放入arr数组中 } stack.add(length); //栈放坐标 length++; head = head.next; } int[] result = new int[length]; //遍历数组放入result for(int i = 0;i < length; i++){ result[i] = arr[i]; } return result; } }
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { //定义头尾节点为null ListNode head = null; ListNode tail = null; //进位 int carry = 0; while(l1 != null || l2 != null){ int n1 = l1 != null ? l1.val : 0; int n2 = l2 != null ? l2.val : 0; int sum = n1 + n2 + carry; if(head == null){ //首尾在同一位置 head = tail = new ListNode(sum % 10); }else{ //尾节点后移 tail.next = new ListNode(sum % 10); tail = tail.next; } //进位最大为1,如9+9=18 carry = sum > 9 ? 1 : 0; if(l1 != null){ l1 = l1.next; } if(l2 != null){ l2 = l2.next; } } //如果最后还有进位尾节点下一位为1 if(carry > 0){ tail.next = new ListNode(carry); } return head; } }
时间复杂度:O(max(m,n)),其中m和n分别为两个链表的长度。我们要遍历两个链表的全部位置,而处理每个位置只需要 O(1)的时间。
空间复杂度:O(1)。注意返回值不计入空间复杂度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。