深入浅出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. 递归与迭代:根据问题特点选择合适的实现方式

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

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

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

相关推荐
火柴就是我11 分钟前
git rebase -i 修改某次提交的message
android
zhangphil23 分钟前
Android ExifInterface rotationDegrees图旋转角度,Kotlin
android·kotlin
火柴就是我27 分钟前
需求开发提交了几个 commit,提交 master 领导 review 后,说你第一笔 commit 代码有问题,让你改一下,怎么办?
android
KdanMin1 小时前
Android系统通知机制深度解析:Framework至SystemUI全链路剖析
android
Wgllss4 小时前
Android下载进度百分比按钮,Compose轻松秒杀实现
android·架构·android jetpack
顾林海5 小时前
深度解析LinkedHashMap工作原理
android·java·面试
JasonYin5 小时前
Git提交前缀
android
louisgeek6 小时前
Android 类加载机制
android
碎风,蹙颦6 小时前
Android开发过程中遇到的SELINUX权限问题
android·人工智能
HZW89706 小时前
鸿蒙应用开发—数据持久化之SQLite
android·前端·harmonyos