算法面试题整理(Java语言)

1、反转链表

/**
 * 这个示例代码中,我们定义了一个 ListNode 类来表示链表的节点,
 * 其中包含一个整数值 val 和一个指向下一个节点的指针 next 。
 * 然后,我们定义了一个 ReverseLinkedList 类来实现链表反转的功能。
 * 在 reverse 方法中,我们使用三个指针 prev 、 current 和 next 来遍历链表并反转指针的指向。
 * 最后,我们使用 main 方法来测试代码,创建一个包含5个节点的链表,并输出反转后的链表结果。
 */
public class ReverseLinkedList {
    public ListNode reverse(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        ListNode prev = null;
        ListNode current = head;
        ListNode next = null;

        while (current != null) {
            next = current.next;
            current.next = prev;
            prev = current;
            current = next;
        }

        return prev;
    }

    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        ReverseLinkedList solution = new ReverseLinkedList();
        ListNode reversedHead = solution.reverse(head);

        // 输出反转后的链表
        while (reversedHead != null) {
            System.out.print(reversedHead.val + " ");
            reversedHead = reversedHead.next;
        }
    }
}

class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
    }
}

2、判断字符串对称

在Java中,判断一个字符串是否对称是一个常见的问题。一个字符串对称指的是它的前半部分和后半部分镜像对称,也就是从中间位置开始,左右对称的字符串。例如,"abcba"和"abccba"都是对称的字符串。

方法一:使用StringBuilder反转字符串

一个简单的方法是使用Java的StringBuilder类来反转字符串,然后判断反转后的字符串是否与原始字符串相等。如果相等,则表示字符串是对称的。

下面是使用StringBuilder反转字符串的代码示例:

public class StringPalindrome {
    public static boolean isPalindrome(String str) {
        StringBuilder reversed = new StringBuilder(str).reverse();
        return str.equals(reversed.toString());
    }

    public static void main(String[] args) {
        String str1 = "abcba";
        // 输出 true
        System.out.println(isPalindrome(str1));

        String str2 = "abccba";
        // 输出 true
        System.out.println(isPalindrome(str2));

        String str3 = "abcd";
        // 输出 false
        System.out.println(isPalindrome(str3));
    }
}

上述代码中的isPalindrome方法接受一个字符串作为参数,并使用StringBuilder类的reverse方法对字符串进行反转。然后,将反转后的字符串与原始字符串进行比较,如果相等,则返回true,否则返回false。

运行上述代码,将会输出以下结果:

true
true
false

方法二:使用双指针

另一种常用的方法是使用双指针来判断字符串是否对称。双指针分别指向字符串的首尾,然后依次比较两个指针所指向的字符是否相等。如果相等,则将指针向中间移动;如果不相等,则表示字符串不对称。

下面是使用双指针判断字符串对称性的代码示例:

public class StringPalindrome {
    public static boolean isPalindrome(String str) {
        int left = 0;
        int right = str.length() - 1;
        while (left < right) {
            if (str.charAt(left) != str.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

    public static void main(String[] args) {
        String str1 = "abcba";
        System.out.println(isPalindrome(str1)); // 输出 true

        String str2 = "abccba";
        System.out.println(isPalindrome(str2)); // 输出 true

        String str3 = "abcd";
        System.out.println(isPalindrome(str3)); // 输出 false
    }
}

上述代码中的isPalindrome方法使用两个指针left和right来比较字符串的首尾字符。如果两个字符不相等,则返回false;否则,将指针向中间移动一位,继续比较下一个字符。当left大于等于right时,表示已经比较完毕,字符串是对称的。

运行上述代码,将会输出以下结果:

true
true
false

3、树的最短路径

import java.util.ArrayList;
import java.util.List;

public class ShortestPath {

    private static class Node {
        int data;
        List<Node> neighbors;

        public Node(int data) {
            this.data = data;
            this.neighbors = new ArrayList<>();
        }
    }

    public static void main(String[] args) {
        // 创建一个树
        Node root = new Node(0);
        root.neighbors.add(new Node(1));
        root.neighbors.add(new Node(2));
        root.neighbors.add(new Node(3));

        // 计算树的最短路径
        List<Node> shortestPath = findShortestPath(root, 3);

        // 打印最短路径
        for (Node node : shortestPath) {
            System.out.println(node.data);
        }
    }

    private static List<Node> findShortestPath(Node root, int target) {
        // 创建一个队列来存储待访问的节点
        Queue<Node> queue = new LinkedList<>();

        // 将根节点加入到队列中
        queue.add(root);

        // 创建一个哈希表来存储每个节点的距离
        Map<Node, Integer> distanceMap = new HashMap<>();
        distanceMap.put(root, 0);

        while (!queue.isEmpty()) {
            // 从队列中弹出一个节点
            Node node = queue.poll();

            // 遍历节点的所有邻居
            for (Node neighbor : node.neighbors) {
                // 如果邻居节点没有被访问过,则将其加入到队列中
                if (!distanceMap.containsKey(neighbor)) {
                    queue.add(neighbor);
                }

                // 更新邻居节点的距离
                distanceMap.put(neighbor, distanceMap.get(node) + 1);
            }
        }

        // 返回最短路径
        return getShortestPath(root, target, distanceMap);
    }

    private static List<Node> getShortestPath(Node root, int target, Map<Node, Integer> distanceMap) {
        // 创建一个列表来存储最短路径
        List<Node> shortestPath = new ArrayList<>();

        // 从目标节点开始,依次找到最短路径上的所有节点
        Node currentNode = target;
        while (currentNode != null) {
            shortestPath.add(currentNode);
            currentNode = distanceMap.get(currentNode) == 0 ? null : distanceMap.get(currentNode) - 1;
        }

        // 反转列表,得到最短路径
        Collections.reverse(shortestPath);

        return shortestPath;
    }
}

4、二分查找

import java.util.Arrays;

public class BinarySearch {

    public static void main(String[] args) {
        // 创建一个数组
        int[] array = {1, 3, 5, 7, 9};

        // 查找元素 5
        int index = binarySearch(array, 5);

        // 打印元素的索引
        System.out.println(index);
    }

    private static int binarySearch(int[] array, int target) {
        // 定义左边界和右边界
        int left = 0;
        int right = array.length - 1;

        // 循环查找
        while (left <= right) {
            // 计算中间位置
            int mid = (left + right) / 2;

            // 如果中间位置的元素等于目标元素,则返回中间位置的索引
            if (array[mid] == target) {
                return mid;
            }

            // 如果中间位置的元素大于目标元素,则将右边界更新为中间位置 - 1
            else if (array[mid] > target) {
                right = mid - 1;
            }

            // 如果中间位置的元素小于目标元素,则将左边界更新为中间位置 + 1
            else {
                left = mid + 1;
            }
        }

        // 如果没有找到目标元素,则返回 -1
        return -1;
    }
}

运行结果

2

5、快速排序

import java.util.Arrays;

public class QuickSort {

    public static void main(String[] args) {
        // 创建一个数组
        int[] array = {1, 3, 5, 7, 9, 2, 4, 6, 8};

        // 快速排序
        quickSort(array, 0, array.length - 1);

        // 打印排序后的数组
        System.out.println(Arrays.toString(array));
    }

    private static void quickSort(int[] array, int left, int right) {
        // 如果左边界大于右边界,则退出递归
        if (left >= right) {
            return;
        }

        // 选择基准元素
        int pivot = array[left];

        // 将小于基准元素的元素放到左边,将大于基准元素的元素放到右边
        int i = left;
        int j = right;
        while (i <= j) {
            while (array[i] < pivot) {
                i++;
            }
            while (array[j] > pivot) {
                j--;
            }
            if (i <= j) {
                int temp = array[i];
                array[i] = array[j];
                array[j] = temp;
                i++;
                j--;
            }
        }

        // 递归对左边和右边的子数组进行排序
        quickSort(array, left, j);
        quickSort(array, i, right);
    }
}

运行结果

[1, 2, 3, 4, 5, 6, 7, 8, 9]

6、冒泡排序

java 
import java.util.Arrays; 
 
public class BubbleSort { 
 
    public static void main(String[] args) { 
        // 创建一个数组 
        int[] array = {5, 3, 8, 2, 1}; 
 
        // 冒泡排序 
        bubbleSort(array); 
 
        // 打印排序后的数组 
        System.out.println(Arrays.toString(array)); 
    } 
 
    private static void bubbleSort(int[] array) { 
        int n = array.length; 
 
        // 外层循环控制排序的轮数 
        for (int i = 0; i < n - 1; i++) { 
            // 内层循环控制每一轮的比较和交换 
            for (int j = 0; j < n - i - 1; j++) { 
                // 如果相邻的两个元素顺序错误,则交换它们 
                if (array[j] > array[j + 1]) { 
                    int temp = array[j]; 
                    array[j] = array[j + 1]; 
                    array[j + 1] = temp; 
                } 
            } 
        } 
    } 
}

运行结果

[1, 2, 3, 5, 8]

7、判断链表中是否有环

public class LinkedListCycle {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }

        ListNode slow = head;
        ListNode fast = head.next;

        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }

        return true;
    }

    public static void main(String[] args) {
        // 构建一个有环的链表
        ListNode head = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);
        ListNode node4 = new ListNode(4);
        ListNode node5 = new ListNode(5);
        head.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        node5.next = node2; // 使链表成环

        LinkedListCycle solution = new LinkedListCycle();
        boolean hasCycle = solution.hasCycle(head);
        System.out.println(hasCycle); // 输出结果为true,表示链表有环
    }
}

/**
 * 链表的节点类
 */
public class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
    }
}

8、二叉树

public class BinaryTree {

    private Node root;

    public BinaryTree() {
        this.root = null;
    }

    public void add(int data) {
        Node newNode = new Node(data);
        if (this.root == null) {
            this.root = newNode;
        } else {
            add(newNode, this.root);
        }
    }

    private void add(Node newNode, Node currentNode) {
        if (newNode.data < currentNode.data) {
            if (currentNode.left == null) {
                currentNode.left = newNode;
            } else {
                add(newNode, currentNode.left);
            }
        } else {
            if (currentNode.right == null) {
                currentNode.right = newNode;
            } else {
                add(newNode, currentNode.right);
            }
        }
    }

    public void inorder() {
        inorder(this.root);
    }

    private void inorder(Node node) {
        if (node != null) {
            inorder(node.left);
            System.out.println(node.data);
            inorder(node.right);
        }
    }

    public void preorder() {
        preorder(this.root);
    }

    private void preorder(Node node) {
        if (node != null) {
            System.out.println(node.data);
            preorder(node.left);
            preorder(node.right);
        }
    }

    public void postorder() {
        postorder(this.root);
    }

    private void postorder(Node node) {
        if (node != null) {
            postorder(node.left);
            postorder(node.right);
            System.out.println(node.data);
        }
    }

    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();
        tree.add(10);
        tree.add(5);
        tree.add(15);
        tree.add(2);
        tree.add(7);
        tree.add(12);
        tree.add(17);

        System.out.println("Inorder traversal:");
        tree.inorder();

        System.out.println("Preorder traversal:");
        tree.preorder();

        System.out.println("Postorder traversal:");
        tree.postorder();
    }
}

9、LRU算法

import java.util.HashMap;
import java.util.Map;

public class LRUCache {

    private final int capacity;

    private final Map<Integer, Node> map;

    private final Node head;

    private final Node tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<>(capacity);
        this.head = new Node();
        this.tail = new Node();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        Node node = map.get(key);
        if (node == null) {
            return -1;
        }
        // 将节点移到链表头部
        removeNode(node);
        addToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        Node node = map.get(key);
        if (node == null) {
            // 缓存中没有该节点,创建一个新的节点
            node = new Node(key, value);
            map.put(key, node);
            // 添加到链表头部
            addToHead(node);
        } else {
            // 缓存中有该节点,更新节点的值
            node.value = value;
            // 将节点移到链表头部
            removeNode(node);
            addToHead(node);
        }

        // 如果缓存的大小超过了容量,则删除链表尾部的节点
        if (map.size() > capacity) {
            Node tail = removeTail();
            map.remove(tail.key);
        }
    }

    private void removeNode(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void addToHead(Node node) {
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
        node.prev = head;
    }

    private Node removeTail() {
        Node node = new Node();
        Node tail = node.prev;
        removeNode(tail);
        return tail;
    }

    private static class Node {

        private int key;

        private int value;

        private Node prev;

        private Node next;

        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }

        public Node() {
            
        }
    }
}

10、数组合并

方法一:

int[] arr1 = {1, 2, 3};
int[] arr2 = {4, 5, 6};

int[] result = new int[arr1.length + arr2.length];
System.arraycopy(arr1, 0, result, 0, arr1.length);
System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
for (int i = 0; i < result.length; i++) {
    System.out.println(result[i]);
}

方法一:

int[] arr1 = {1, 2, 3};
int[] arr2 = {4, 5, 6};

int[] result = Arrays.copyOf(arr1, arr1.length + arr2.length);
System.arraycopy(arr2, 0, result, arr1.length, arr2.length);

for (int i = 0; i < result.length; i++) {
    System.out.println(result[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值