数据结构常见面试题及详细java示例

下面是一些常见的数据结构面试题以及使用Java实现的解决方案。

1、如何在给定数组中找到重复的元素?

        使用HashSet是一个常见的解决方法。

public class FindDuplicates {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 1, 2, 4};
        Set<Integer> set = new HashSet<>();

        for (int num : array) {
            if (!set.add(num)) {
                System.out.println("重复的元素是:" + num);
            }
        }
    }
}

2、链表反转

        反转链表是最常见的数据结构问题之一。以下是用Java实现的一个例子。

class ListNode {
      int val;
      ListNode next;
      ListNode() {}
      ListNode(int val) { this.val = val; }
      ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

public class ReverseLinkedList {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode current = head;
        while (current != null) {
            ListNode nextTemp = current.next;
            current.next = prev;
            prev = current;
            current = nextTemp;
        }
        return prev;
    }
}

3、二叉树的深度

       这个问题可以使用递归来解决。

class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode(int x) { val = x; }
}

public class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        else {
            int leftHeight = maxDepth(root.left);
            int rightHeight = maxDepth(root.right);
            return Math.max(leftHeight, rightHeight) + 1;
        }
    }
}

4、如何在给定数组中找到缺失的数?

        我们可以使用异或来找到缺失的数字,因为异或操作满足交换律和结合律。

public class MissingNumber {
    public static int findMissingNumber(int[] arr) {
        int n = arr.length;
        int x1 = arr[0];
        int x2 = 1;
        
        for (int i = 1; i < n; i++) {
            x1 = x1 ^ arr[i];
        }
        
        for (int i = 2; i <= n + 1; i++) {
            x2 = x2 ^ i;
        }
        
        return x1 ^ x2;
    }
    
    public static void main(String[] args) {
        int[] arr = {1, 2, 4, 6, 3, 7, 8};
        System.out.println("Missing number: " + findMissingNumber(arr));
    }
}

5、如何实现一个队列使用两个栈?

public class QueueWithTwoStacks {
    private Stack<Integer> s1 = new Stack<Integer>();
    private Stack<Integer> s2 = new Stack<Integer>();

    public void enqueue(int item) {
        s1.push(item);
    }

    public int dequeue() {
        if (s2.isEmpty()) {
            while (!s1.isEmpty()) {
                s2.push(s1.pop());
            }
        }
        return s2.pop();
    }
}

6、如何从链表中删除倒数第n个节点?

        这种问题可以通过快慢指针来解决。

public class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;

        for (int i = 1; i <= n + 1; i++) {
            fast = fast.next;
        }

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

        slow.next = slow.next.next;

        return dummy.next;
    }
}

7、如何检查字符串中的括号是否正确配对?

        这是一个典型的利用栈数据结构来处理的问题。当遇到左括号时,我们把它压入栈中,当遇到右括号时,我们检查栈是否为空以及栈顶的左括号是否与之配对,如果配对则弹出栈顶元素,最后栈应该是空的。

public boolean isValid(String s) {
    Stack<Character> stack = new Stack<Character>();
    for (char c : s.toCharArray()) {
        if (c == '(')
            stack.push(')');
        else if (c == '[')
            stack.push(']');
        else if (c == '{')
            stack.push('}');
        else if (stack.isEmpty() || stack.pop() != c)
            return false;
    }
    return stack.isEmpty();
}

8、如何从给定数组中找到前k大的元素?

        这个问题可以用优先队列实现。Java里的优先队列用的是堆排序。

public List<Integer> findTopK(int[] nums, int k) {
    PriorityQueue<Integer> pq = new PriorityQueue<>(); // 小顶堆
    for (int val : nums) {
        pq.add(val);
        if (pq.size() > k)  // 如果加入后大小超过k,则队头元素出队
            pq.poll();
    }
    List<Integer> res = new ArrayList<>(pq);
    Collections.sort(res, Collections.reverseOrder());  // 降序排列
    return res;
}

9、二叉树的层次遍历

        这个问题可以通过使用队列进行广度优先遍历(BFS)来解决。

public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> levels = new ArrayList<List<Integer>>();
    if (root == null) return levels;

    Queue<TreeNode> queue = new LinkedList<TreeNode>();
    queue.add(root);

    while (!queue.isEmpty()) {
        List<Integer> level = new ArrayList<Integer>();
        int levelSize = queue.size();
        for (int i = 0; i < levelSize; ++i) {
            TreeNode node = queue.remove();
            level.add(node.val);
            if (node.left != null) queue.add(node.left);
            if (node.right != null) queue.add(node.right);
        }
        levels.add(level);
    }
    return levels;
}

10、合并K个有序链表

        这个问题可以通过优先队列来解决,通过逐一比较链表的节点(最小堆)。

public class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> queue = new PriorityQueue<>(Comparator.comparingInt(l -> l.val));
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        
        for (ListNode node : lists) {
            if (node!= null) {
                queue.add(node);
            }      
        }
        
        while (!queue.isEmpty()) {
            curr.next = queue.poll();
            curr = curr.next;
            if (curr.next != null) {
                queue.add(curr.next);
            }
        }
        return dummy.next;
    }
}

11、二叉树中的最大路径和

        这类问题可以使用分治的思想,通过递归来解决。

class Solution {
    int max_sum = Integer.MIN_VALUE;

    public int max_gain(TreeNode node) {
        if (node == null) return 0;

        // 递归计算左右子节点的最大贡献值
        // 只有在贡献值大于 0 时,才会选取对应子节点
        int left_gain = Math.max(max_gain(node.left), 0);
        int right_gain = Math.max(max_gain(node.right), 0);

        // 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
        int price_newpath = node.val + left_gain + right_gain;

        // 更新答案
        max_sum = Math.max(max_sum, price_newpath);

        // 返回节点的最大贡献值
        return node.val + Math.max(left_gain, right_gain);
    }

    public int maxPathSum(TreeNode root) {
        max_gain(root);
        return max_sum;
    }
}

12、找到数组中第K个最大的元素

        这种题目可以通过快速选择来解决,这是基于快速排序的一种优化算法。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        k = nums.length - k; // convert it to 'kth smallest'
        int lo = 0; 
        int hi = nums.length - 1;
        while (lo < hi) {
            final int j = partition(nums, lo, hi);
            if(j < k) {
                lo = j + 1;
            } else if (j > k) {
                hi = j - 1;
            } else {
                break;
            }
        }
        return nums[k];
    }

    private int partition(int[] a, int lo, int hi) {
        int i = lo;
        int j = hi + 1;
        while(true) {
            while(a[++i] < a[lo] && i < hi);
            while(a[--j] > a[lo] && j > lo);
            if(i >= j) {
                break;
            }
            swap(a, i, j);
        }
        swap(a, lo, j);
        return j;
    }

    private void swap(int[] a, int i, int j) {
        final int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }  
}

  • 15
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一些常见Java面试题及其答案: 1. 什么是Java中的面向对象编程(OOP)?列举OOP的原则。 面向对象编程是一种编程范式,它将数据和操作数据的方法组合成对象。Java是一种面向对象的编程语言,它支持封装、继承和多态等OOP原则。 OOP的原则包括: - 封装:将数据和操作数据的方法封装在一个对象中,通过访问修饰符来控制对数据的访问。 - 继承:通过继承机制,一个类可以继承另一个类的属性和方法。 - 多态:同一种类型的对象,在不同的情况下可以表现出不同的行为。 2. 什么是Java中的重载和重写?它们之间有什么区别? 重载(Overloading)是指在同一个类中,可以有多个方法具有相同的名称,但参数列表不同。重载方法可以根据不同的参数类型和个数进行调用。 重写(Overriding)是指子类重新定义了父类中已有的方法。重写方法必须具有相同的名称、参数列表和返回类型。重写方法可以在子类中实现特定的行为。 区别: - 重载是在同一个类中定义多个方法,方法名相同但参数列表不同;重写是子类重新定义父类中已有的方法。 - 重载是编译时多态性,根据参数类型和个数选择调用的方法;重写是运行时多态性,根据对象的实际类型选择调用的方法。 3. Java中的异常处理机制是什么? Java中的异常处理机制通过try-catch语句块来处理异常。在try块中编写可能抛出异常的代码,如果发生异常,会跳转到catch块中执行相应的处理逻辑。 示例代码: ```java try { // 可能抛出异常的代码 } catch (Exception e) { // 异常处理逻辑 } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哎 你看

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值