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

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

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

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

相关推荐
selt7912 分钟前
Redisson之RedissonLock源码完全解析
android·java·javascript
Yao_YongChao37 分钟前
Android MVI处理副作用(Side Effect)
android·mvi·mvi副作用
非凡ghost2 小时前
JRiver Media Center(媒体管理软件)
android·学习·智能手机·媒体·软件需求
席卷全城2 小时前
Android 推箱子实现(引流文章)
android
齊家治國平天下2 小时前
Android 14 系统中 Tombstone 深度分析与解决指南
android·crash·系统服务·tombstone·android 14
maycho1234 小时前
MATLAB环境下基于双向长短时记忆网络的时间序列预测探索
android
思成不止于此4 小时前
【MySQL 零基础入门】MySQL 函数精讲(二):日期函数与流程控制函数篇
android·数据库·笔记·sql·学习·mysql
brave_zhao5 小时前
达梦数据库(DM8)支持全文索引功能,但并不直接兼容 MySQL 的 FULLTEXT 索引语法
android·adb
sheji34165 小时前
【开题答辩全过程】以 基于Android的网上订餐系统为例,包含答辩的问题和答案
android
easyboot5 小时前
C#使用SqlSugar操作mysql数据库
android·sqlsugar