返回

从尾到头打印链表(Offer 06、07)

前端

如何替换字符串中的空格并从尾到头打印链表

1. 概述

在编程面试中,经常会遇到一些经典的算法问题,例如替换字符串中的空格和从尾到头打印链表。本文将详细介绍这两种问题的解决方案,并提供一些扩展思考。

2. 替换字符串中的空格

2.1 问题

给定一个字符串 s,请将字符串中的每个空格替换成 "%20"。

2.2 解决方案

方法 1:使用 StringBuilder

最简单的方法是使用 StringBuilder 类。我们可以遍历字符串,并将每个空格字符替换为 "%20"。以下是代码示例:

public String replaceSpaces(String s) {
  if (s == null || s.length() == 0) {
    return "";
  }

  StringBuilder sb = new StringBuilder();
  for (char c : s.toCharArray()) {
    if (c == ' ') {
      sb.append("%20");
    } else {
      sb.append(c);
    }
  }

  return sb.toString();
}

方法 2:使用正则表达式

另一种方法是使用正则表达式。正则表达式可以匹配字符串中的特定模式,并对其进行替换。以下是使用正则表达式的代码示例:

public String replaceSpaces(String s) {
  return s.replaceAll(" ", "%20");
}

3. 从尾到头打印链表

3.1 问题

给定一个链表,请从尾到头打印该链表的每个节点的值。

3.2 解决方案

方法 1:使用栈

我们可以使用栈来解决这个问题。栈是一种先进后出的数据结构。我们可以遍历链表,并把每个节点的值压入栈中。然后,我们可以依次弹出栈中的元素,并打印其值。以下是代码示例:

public List<Integer> printLinkedListFromTailToHead(ListNode head) {
  List<Integer> result = new ArrayList<>();

  if (head == null) {
    return result;
  }

  Stack<Integer> stack = new Stack<>();
  ListNode cur = head;
  while (cur != null) {
    stack.push(cur.val);
    cur = cur.next;
  }

  while (!stack.isEmpty()) {
    result.add(stack.pop());
  }

  return result;
}

方法 2:递归

我们也可以使用递归来解决这个问题。递归是一种函数调用自身的方法。我们可以递归地遍历链表,并在每次递归调用中将节点的值添加到结果列表中。以下是代码示例:

public List<Integer> printLinkedListFromTailToHead(ListNode head) {
  List<Integer> result = new ArrayList<>();

  if (head == null) {
    return result;
  }

  result.addAll(printLinkedListFromTailToHead(head.next));
  result.add(head.val);

  return result;
}

4. 扩展思考

4.1 替换字符串中的空格

  • 可以使用 Java 的 String.replace() 方法直接进行替换。
public String replaceSpaces(String s) {
  return s.replace(" ", "%20");
}

4.2 从尾到头打印链表

  • 可以使用双指针法来解决这个问题。
public List<Integer> printLinkedListFromTailToHead(ListNode head) {
  List<Integer> result = new ArrayList<>();

  if (head == null) {
    return result;
  }

  ListNode slow = head;
  ListNode fast = head;
  while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
  }

  while (slow != null) {
    result.add(slow.val);
    slow = slow.next;
  }

  return result;
}

5. 常见问题解答

5.1 为什么使用 StringBuilder 代替 String?

StringBuilder 是一种可变字符串,可以高效地进行字符串拼接。而 String 是不可变的,每次拼接都会创建一个新的字符串对象。使用 StringBuilder 可以避免频繁创建新对象,提高效率。

5.2 为什么使用栈来从尾到头打印链表?

栈是一种先进后出的数据结构,可以方便地实现从尾到头的打印顺序。我们可以将节点的值压入栈中,然后依次弹出栈中的元素进行打印。

5.3 双指针法和递归哪个效率更高?

双指针法和递归的效率都与链表的长度成正比。然而,双指针法在空间复杂度上更优,因为它只需要两个指针变量,而递归需要额外的栈空间。

5.4 可以使用队列来从尾到头打印链表吗?

可以。队列是一种先进先出的数据结构,我们可以将节点的值入队,然后依次出队进行打印。但是,使用队列的效率会比使用栈低,因为队列需要额外的空间来存储节点的顺序。

5.5 如何处理链表中存在环的情况?

如果链表中存在环,那么使用递归和双指针法都会陷入死循环。我们可以使用哈希表来检测环的存在,并根据情况进行处理。