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

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

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

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

相关推荐
居然是阿宋6 分钟前
Android Canvas API 详细说明与示例
android
wuli玉shell3 小时前
spark-Schema 定义字段强类型和弱类型
android·java·spark
东风西巷3 小时前
BLURRR剪辑软件免费版:创意剪辑,轻松上手,打造个性视频
android·智能手机·音视频·生活·软件需求
JhonKI3 小时前
【MySQL】行结构详解:InnoDb支持格式、如何存储、头信息区域、Null列表、变长字段以及与其他格式的对比
android·数据库·mysql
ab_dg_dp4 小时前
Android 位掩码操作(&和~和|的二进制运算)
android
潜龙952716 小时前
第3.2.3节 Android动态调用链路的获取
android·调用链路
追随远方17 小时前
Android平台FFmpeg音视频开发深度指南
android·ffmpeg·音视频
撰卢18 小时前
MySQL 1366 - Incorrect string value:错误
android·数据库·mysql
恋猫de小郭18 小时前
Flutter 合并 ‘dot-shorthands‘ 语法糖,Dart 开始支持交叉编译
android·flutter·ios
牛马程序小猿猴18 小时前
15.thinkphp的上传功能
android