深入浅出Java算法:数组与链表处理类问题

深入浅出Java算法:数组与链表处理类问题

数组和链表是最基础的数据结构,掌握它们的处理技巧是算法学习的关键。下面我将用通俗易懂的方式介绍常见的数组和链表处理问题及其解决方案。

一、数组篇

1. 两数之和

问题:在数组中找到两个数,使它们的和等于目标值

java 复制代码
public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {
            return new int[] {map.get(complement), i};
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

2. 移动零

问题:将数组中的零移动到末尾,保持其他元素相对顺序

java 复制代码
public void moveZeroes(int[] nums) {
    int nonZeroIndex = 0;
    // 将非零元素前移
    for (int num : nums) {
        if (num != 0) {
            nums[nonZeroIndex++] = num;
        }
    }
    // 剩余位置补零
    while (nonZeroIndex < nums.length) {
        nums[nonZeroIndex++] = 0;
    }
}

3. 盛最多水的容器

问题:找出两条线,使它们与x轴构成的容器能容纳最多的水

java 复制代码
public int maxArea(int[] height) {
    int max = 0, left = 0, right = height.length - 1;
    while (left < right) {
        int area = Math.min(height[left], height[right]) * (right - left);
        max = Math.max(max, area);
        if (height[left] < height[right]) {
            left++;
        } else {
            right--;
        }
    }
    return max;
}

4. 三数之和

问题:找出数组中所有和为0的三元组(不重复)

java 复制代码
public List<List<Integer>> threeSum(int[] nums) {
    Arrays.sort(nums);
    List<List<Integer>> res = new ArrayList<>();
    for (int i = 0; i < nums.length - 2; i++) {
        if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
        
        int left = i + 1, right = nums.length - 1;
        while (left < right) {
            int sum = nums[i] + nums[left] + nums[right];
            if (sum == 0) {
                res.add(Arrays.asList(nums[i], nums[left], nums[right]));
                while (left < right && nums[left] == nums[left + 1]) left++; // 去重
                while (left < right && nums[right] == nums[right - 1]) right--; // 去重
                left++;
                right--;
            } else if (sum < 0) {
                left++;
            } else {
                right--;
            }
        }
    }
    return res;
}

二、链表篇

1. 反转链表

问题:将单链表反转

java 复制代码
public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode nextTemp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = nextTemp;
    }
    return prev;
}

2. 合并两个有序链表

问题:将两个升序链表合并为一个新的升序链表

java 复制代码
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode dummy = new ListNode(0);
    ListNode current = dummy;
    
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            current.next = l1;
            l1 = l1.next;
        } else {
            current.next = l2;
            l2 = l2.next;
        }
        current = current.next;
    }
    
    current.next = l1 != null ? l1 : l2;
    return dummy.next;
}

3. 链表中环的检测

问题:判断链表中是否有环

java 复制代码
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;
}

4. 删除链表的倒数第N个节点

问题:删除链表的倒数第n个节点

java 复制代码
public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode first = dummy;
    ListNode second = dummy;
    
    // 先让first指针移动n+1步
    for (int i = 1; i <= n + 1; i++) {
        first = first.next;
    }
    
    // 然后两个指针一起移动,直到first到达末尾
    while (first != null) {
        first = first.next;
        second = second.next;
    }
    
    second.next = second.next.next;
    return dummy.next;
}

三、数组与链表综合问题

1. 重排链表

问题:将链表 L0→L1→...→Ln-1→Ln 重排为 L0→Ln→L1→Ln-1→L2→Ln-2→...

java 复制代码
public void reorderList(ListNode head) {
    if (head == null || head.next == null) return;
    
    // 1. 找到中间节点
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    
    // 2. 反转后半部分链表
    ListNode prev = null, curr = slow;
    while (curr != null) {
        ListNode nextTemp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = nextTemp;
    }
    
    // 3. 合并两个链表
    ListNode first = head, second = prev;
    while (second.next != null) {
        ListNode temp1 = first.next;
        ListNode temp2 = second.next;
        first.next = second;
        second.next = temp1;
        first = temp1;
        second = temp2;
    }
}

2. 旋转数组

问题:将数组向右旋转k个位置

java 复制代码
public void rotate(int[] nums, int k) {
    k %= nums.length;
    reverse(nums, 0, nums.length - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, nums.length - 1);
}

private void reverse(int[] nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start++;
        end--;
    }
}

总结

处理数组和链表问题的常用技巧:

  1. 双指针技巧:适用于有序数组、链表反转、环检测等问题
  2. 哈希表辅助:快速查找元素,如两数之和问题
  3. 快慢指针:解决链表中间节点、环检测等问题
  4. 虚拟头节点:简化链表操作,避免处理头节点的特殊情况
  5. 递归与迭代:根据问题特点选择合适的实现方式

记住解决这类问题的关键步骤:

  • 明确问题要求
  • 画图辅助理解(特别是链表问题)
  • 考虑边界条件(空数组/链表、单个元素等)
  • 选择合适的数据结构和算法

掌握这些基础问题的解法,能够帮助你更好地应对更复杂的算法问题!

相关推荐
Digitally23 分钟前
如何将文件从 iPhone 传输到 Android(新指南)
android·ios·iphone
whysqwhw1 小时前
OkHttp深度架构缺陷分析与演进规划
android
用户7093722538511 小时前
Android14 SystemUI NotificationShadeWindowView 加载显示过程
android
木叶丸2 小时前
跨平台方案该如何选择?
android·前端·ios
顾林海3 小时前
Android ClassLoader加载机制详解
android·面试·源码
用户2018792831673 小时前
🎨 童话:Android画布王国的奇妙冒险
android
whysqwhw3 小时前
OkHttp框架的全面深入架构分析
android
你过来啊你3 小时前
Android App冷启动流程详解
android
泓博4 小时前
KMP(Kotlin Multiplatform)改造(Android/iOS)老项目
android·ios·kotlin
移动开发者1号4 小时前
使用Baseline Profile提升Android应用启动速度的终极指南
android·kotlin