环形链表插值练习题
有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序。
给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。
测试样例:
[1,3,4,5,7],[1,2,3,4,0],2
返回:{1,2,3,4,5,7}
分析:
一共有三种情况
1、如果原链表为空
2、如果链表不为空
3、如果p和c转一圈都没有发现应该插入的位置,此时node应该插入头节点的前面
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class InsertValue {
public ListNode insert(int[] A, int[] nxt, int val) {
if (A == null || A.length == 0){
ListNode node = new ListNode(val);
return node;
}
ListNode head = new ListNode(A[0]);
// 构建有序链表(并非环形,因为不能题目不让返回环形)
ListNode headTemp = head;
for (int i = 0; i < A.length-1; i++){
ListNode temp = new ListNode(A[nxt[i]]);
headTemp.next = temp;
headTemp = temp;
}
// 如果值小于链表头部值,则插入头部,且返回node链表
if (val < head.val){
ListNode node = new ListNode(val);
node.next = head;
return node;
}
// 循环遍历,寻找合适的位置插入
ListNode pre = head;
ListNode cur = pre.next;
while (cur != null){
if (val >= pre.val && val <= cur.val){
break;
}
pre = cur;
cur = cur.next;
}
// 要么是找到了合适的位置(break出来),要么是val都大于链表值,在最后位置插入
ListNode node = new ListNode(val);
node.next = cur;
pre.next = node;
return head;
}
}
访问单个节点的删除练习题
实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。
给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true
分析:
1、下一个节点指向删除的节点,然后删除下一个节点
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class Remove {
public boolean removeNode(ListNode pNode) {
// 空节节不能删除
if (pNode == null){
return false;
}
ListNode next = pNode.next;
// 空节点不能赋值给节点
if (next == null){
return false;
}
pNode.val = next.val;
pNode.next = next.next;
return true;
}
}
链表的分化练习题
对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。
给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。
测试样例:
{1,4,2,5},3
返回结果:
{1,2,4,5}
分析:
1、建立两个链表:小于等于val链表,大于val链表
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class Divide {
public ListNode listDivide(ListNode head, int val) {
if (head == null || head.next == null){
return head;
}
// 当前节点
ListNode curNode = head, temp = null;
// 小于val的链表与尾节点
ListNode smallerHead = null, smallerTail = null;
// 与大于val的链表与尾节点
ListNode biggerHead = null, biggerTail = null;
while (curNode != null){
// 取出第一个节点
temp = curNode;
curNode = curNode.next;
// 避免其它链表连接后成为闭环
temp.next = null;
int value = temp.val;
if (value <= val){
// 如果是第一个,则附头
if (smallerHead == null){
smallerHead = temp;
}
// 如果不是第一个,则尾部添加
else{
smallerTail.next = temp;
}
// 尾部指向最后一个
smallerTail = temp;
}
else {
// 如果是第一个,则附头
if (biggerHead == null){
biggerHead = temp;
}
// 如果不是第一个,则尾部添加
else{
biggerTail.next = temp;
}
// 尾部指向最后一个
biggerTail = temp;
}
}
// 如果小的链表没值,则返回大的链表
if (smallerHead == null){
return biggerHead;
}
// 如果大的链表没值,则返回小的链表
if (biggerHead == null){
return smallerHead;
}
// 小链表与大链表连接
smallerTail.next = biggerHead;
return smallerHead;
}
}
打印两个链表的公共值练习题
现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。
给定两个链表的头指针headA和headB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共值
测试样例: {1,2,3,4,5,6,7},{2,4,6,8,10}
返回:[2.4.6]
分析:
1、两数比较,小的自己+1,等于的装进数组,然后都+1
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class Common {
public int[] findCommonParts(ListNode headA, ListNode headB) {
List<Integer> list = new ArrayList<>();
while (headA != null && headB != null){
if (headA.val < headB.val){
headA = headA.next;
}
else if (headA.val > headB.val){
headB = headB.next;
}
else{
list.add(headA.val);
headA = headA.next;
headB = headB.next;
}
}
int[] a = new int[list.size()];
for (int i = 0; i < list.size(); i++)
{
a[i] = list.get(i);
}
return a;
}
}
链表的k逆序练习题
有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。 给定一个单链表的头指针head,同时给定K值,返回逆序后的链表的头指针。
分析:
1、使用栈存储3个数,出栈就是倒序啦。里边有许多的细节需要画图处理的
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class KInverse {
public ListNode inverse(ListNode head, int k) {
if (k < 2){
return head;
}
Stack<ListNode> stack = new Stack<>();
ListNode newHead = head, cur = head;
// 上一个链表的末端,下一个链表的开始
ListNode preEnd = null, nextStart = null;
while (cur != null){
nextStart = cur.next;
stack.push(cur);
if (stack.size() == k){
preEnd = reload(stack, preEnd, nextStart);
// 因为逆序了,所以头结点需要改变(就一次)
if (newHead == head){
newHead = cur;
}
}
cur = nextStart;
}
return newHead;
}
public ListNode reload(Stack<ListNode> stack, ListNode preEnd, ListNode nextStart){
ListNode cur = stack.pop();
// 如果不等于null,则上一个末端(preEnd)直接连接当前(cur)的节点
if (preEnd != null){
preEnd.next = cur;
}
ListNode next = null;
while (!stack.isEmpty()){
next = stack.pop();
cur.next = next;
cur = next;
}
// 三个节点中的最后一个节点与下一个链表(nextStart)连接
cur.next = nextStart;
// 返回当前链表的最后一个节点
return cur;
}
}
链表指定值清除练习题
现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。
给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。
测试样例:
{1,2,3,4,3,2,1},2
返回值:
{1,3,4,3,1}
分析:
1、遍历链表,一样的值则删除掉
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class ClearValue {
public ListNode clear(ListNode head, int val) {
// 避免头部为一样值
while (head != null){
if (head.val != val)
break;
head = head.next;
}
ListNode pre = head;
ListNode cur = head;
// 遍历链表,一样的值则删除
while (cur != null){
if (cur.val == val){
pre.next = cur.next;
}
else {
pre = cur;
}
cur = cur.next;
}
return head;
}
}
链表的回文结构练习题
请编写一个函数,检查链表是否为回文。 给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。
测试样例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
分析:
回文:是否对称
1、将数据全入栈,出栈的时候与链表一一比较,都相等则回文。。
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class Palindrome {
public boolean isPalindrome(ListNode pHead) {
if (pHead == null){
return false;
}
Stack<ListNode> stack = new Stack<>();
// 将节点都放到栈里
ListNode cur = pHead;
while (cur != null){
stack.push(cur);
cur = cur.next;
}
// 出栈,看是否全都相等
ListNode temp = null;
cur = pHead;
while (!stack.isEmpty()){
temp = stack.pop();
if (temp.val != cur.val){
return false;
}
else {
cur = cur.next;
}
}
return true;
}
}
链表判环练习题
如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。
给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。
import java.util.*;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class ChkLoop {
public int chkLoop(ListNode head, int adjust) {
ListNode fast = head;
ListNode slow = head;
boolean circle = false;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
// 当相等时说明是闭环;
if (fast == slow){
circle = true;
break;
}
}
if (circle == false){
return -1;
}
// fast再从头来开始,当它们再次相遇说明是入口点;
fast = head;
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast.val;
}
}