程序员代码面试指南 —— 链表问题(一)

注:题目来自于《程序员代码面试指南:IT名企算法与数据结构题目最优解》,该书是左程云老师的著作,值得推荐,这里仅是记录一下该书中题目的解法和个人理解

题目一:在单链表和双链表中删除倒数第K个节点
描述:
  分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点
思路:
  这里书中给出的方法是设定了一个变量K,用K来判断指针位置,但是我比较喜欢用快慢指针法去解决此类问题,这里给出一种使用快慢指针发的解法。
  单项链表首先设定一个快指针,sign,比head指针先移动k+1个位置,保证在sign走到链表尾节点的时候,head可以指向目标位置前一个节点,然后只需要令head.next = head.next.next即可。
  双向链表更为简单,可以令sign比head指针先移动K个位置,这样在sign指向尾节点的时候,head正好指向要删除的位置,此时只需要将head.last.next = head.next; head.last.last = head.last即可。
  只介绍单项链表的写法
在这里插入图片描述
链表代码:

public class Node {
    public int value;
    public Node next;
    public Node(int data){
        this.value = data;
    }
}

删除方法及测试类:

public class RemoveElement {
  public static void main(String[] args) {
    // init
    Node head = new Node(1);
    Node node1 = new Node(2);
    Node node2 = new Node(3);
    Node node3 = new Node(4);
    head.next = node1;
    node1.next = node2;
    node2.next = node3;
    // test
    System.out.println("删除节点之前:");
    Node h = head;
    while (h != null) {
      System.out.print(h.value + " ");
      h = h.next;
    }
    System.out.println();
    int k = 2;
    removeLastKthNode(head, k);
    System.out.println("删除节点之后:");
    while (head != null) {
      System.out.print(head.value + " ");
      head = head.next;
    }
  }
 
  private static void removeLastKthNode(Node head, int k) {
    if (k < 0) {
      throw new RuntimeException("参数有误");
    }
    Node sign = head;
    while (k-- >= 0) {
      sign = sign.next;
      if (sign == null) {
        throw new RuntimeException("参数有误");
      }
    }
    while (sign != null) {
      sign = sign.next;
      head = head.next;
    }
    head.next = head.next.next;
  }
} 

测试结果,亲测可用:

删除节点之前:
1 2 3 4
删除节点之后:
1 2 4

题目二:删除链表a/b处的节点
问题描述:
  给定链表头节点head,实现删除链表中间节点的函数
例如:
链表1->2->3->4->5 假设a/b的值为r
如果r等于0,不删除任何节点
如果r在区间(0,1/5】上,删除节点1
如果r在区间(1/5,2/5】上,删除节点2

如果r大于1,不删除任何节点
思路:
  问题仅在于确定第几个节点为删除节点,找到该节点的前一节点即可。
图解:
  分析起来并不困难,可以取一个特殊值,以特殊代一般,总结规律,比如链表  长度7 a= 5 b = 6
  5/67=5.83333向上取整为6
  所在区间
  5/6=0.8333
  5/7<5/6<=6/7,删除节点6
结论:
  a/6
链表长度向上取整,既为要删除的节点
链表代码:

public class Node {
    public int value;
    public Node next;
    public Node(int data){
        this.value = data;
    }
}

方法及测试代码:

public class RemoveElementTwo {
  public static void main(String[] args) {
    // init
    Node head = new Node(1);
    Node node1 = new Node(2);
    Node node2 = new Node(3);
    Node node3 = new Node(4);
    Node node4 = new Node(5);
    Node node5 = new Node(6);
    Node node6 = new Node(7);
    head.next = node1;
    node1.next = node2;
    node2.next = node3;
    node3.next = node4;
    node4.next = node5;
    node5.next = node6;
    int a = 5;
    int b = 6;
    // test
    System.out.println("删除节点之前:");
    Node h = head;
    while (h != null) {
      System.out.print(h.value + " ");
      h = h.next;
    }
    System.out.println();
    deleteElement(head, a, b);
    System.out.println("删除节点之后:");
    while (head != null) {
      System.out.print(head.value + " ");
      head = head.next;
    }
  }
 
  private static void deleteElement(Node head, int a, int b) {
    Node h = head;
    int len = 0;
    while (h != null) {
      h = h.next;
      len++;
    }
    //要删除第几个节点
    int num = (int) Math.ceil(a * len / (double) b);
    //找到前一个节点,本身循环就从1节点开始,同时选择删除前一节点 所以2 = 0 + 1+ 1
    for(int i = num;i-2>0;i--){
        head = head.next;
    }
    head.next = head.next.next;
  }
}

执行结果,亲测可用:

删除节点之前:
1 2 3 4 5 6 7
删除节点之后:
1 2 3 4 5 7

猜你喜欢

转载自blog.csdn.net/Kirito19970409/article/details/83823541