AP CSA ArrayList 必考算法
这篇是 AP CSA ArrayList 最常考的“算法模板”合集。每一题基本都能套其中一种(或两种组合)。
0. 基础提醒:ArrayList 常用 API(考试必背)
list.size():元素个数(返回值:int)list.get(i):读取第 i 个元素(返回值:E,也就是列表里存的元素类型,比如Integer/String)list.set(i, value):修改第 i 个元素(返回值:E,返回“被替换掉的旧元素”)list.add(value):末尾添加(返回值:boolean,通常是true)list.add(i, value):在 i 位置插入(原 i 及后面整体右移)(返回值:void)list.remove(i):删除 i 位置元素(后面整体左移)(返回值:E,返回“被删除的元素”)
1. 插入元素 (Insert Elements)
常见场景:按位置插入、按规则插入到有序列表。
A) 在指定位置插入
import java.util.ArrayList;
public class InsertAtIndex {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(10);
list.add(30);
list.add(40);
int index = 1;
int value = 20;
// 在 index 位置插入 value:原 index 及后面元素整体右移
list.add(index, value);
System.out.println(list); // [10, 20, 30, 40]
}
}B) 插入到有序列表(保持升序)
import java.util.ArrayList;
public class InsertSorted {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(5);
list.add(9);
list.add(12);
int x = 8;
// 找到第一个 >= x 的位置
int i = 0;
while (i < list.size() && list.get(i) < x) {
i++;
}
// 在 i 插入:保持升序
list.add(i, x);
System.out.println(list); // [3, 5, 8, 9, 12]
}
}2. 删除元素 (Delete Elements)
ArrayList 删除最容易出错:删除会导致索引“塌陷”,所以通常用 倒序 for 或 while 控制。
A) 删除所有满足条件的元素(推荐:倒序 for)
import java.util.ArrayList;
public class RemoveAllEvens {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(4);
list.add(5);
list.add(6);
// 倒序:remove(i) 后不会影响“尚未访问”的索引
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i) % 2 == 0) {
list.remove(i);
}
}
System.out.println(list); // [1, 5]
}
}B) 只删除第一个满足条件的元素(用布尔控制,不用 break)
import java.util.ArrayList;
public class RemoveFirstMatch {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cat");
list.add("dog");
list.add("duck");
list.add("dolphin");
boolean removed = false;
for (int i = 0; i < list.size() && !removed; i++) {
String s = list.get(i);
// AP CSA 范围内替代 startsWith("do")
// 条件:字符串长度至少为 2,且前两个字符等于 "do"
if (s.length() >= 2 && s.substring(0, 2).equals("do")) {
list.remove(i);
removed = true;
}
}
System.out.println(list); // [cat, duck, dolphin]
}
}3. 寻找最小值或最大值 (Min/Max)
模板:假设第一个是 min/max,再逐个比较更新。
import java.util.ArrayList;
public class MinMaxArrayList {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(7);
nums.add(2);
nums.add(9);
nums.add(4);
int min = nums.get(0);
int max = nums.get(0);
for (int i = 1; i < nums.size(); i++) {
int cur = nums.get(i);
if (cur < min) {
min = cur;
}
if (cur > max) {
max = cur;
}
}
System.out.println("min = " + min); // 2
System.out.println("max = " + max); // 9
}
}4. 计算总和或平均值 (Sum/Average)
平均值注意:强转 double,避免整数除法丢小数。
import java.util.ArrayList;
public class SumAndAverage {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(5);
nums.add(1);
nums.add(7);
int sum = 0;
for (int i = 0; i < nums.size(); i++) {
sum += nums.get(i);
}
double avg = 0.0;
if (nums.size() > 0) {
avg = (double) sum / nums.size();
}
System.out.println("sum = " + sum);
System.out.println("avg = " + avg);
}
}5. 判断是否“至少有一个”元素满足条件 (At Least One)
模板:found=false,循环条件里加 && !found 来提前停止(避免 break)。
import java.util.ArrayList;
public class AtLeastOne {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(3);
nums.add(7);
nums.add(10);
boolean hasEven = false;
for (int i = 0; i < nums.size() && !hasEven; i++) {
if (nums.get(i) % 2 == 0) {
hasEven = true;
}
}
System.out.println("Has even? " + hasEven); // true
}
}6. 判断是否“所有”元素满足条件 (All)
模板:all=true,一旦发现反例就变 false,并提前停止。
import java.util.ArrayList;
public class AllProperty {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(2);
nums.add(4);
nums.add(6);
boolean allEven = true;
int i = 0;
while (i < nums.size() && allEven) {
if (nums.get(i) % 2 != 0) {
allEven = false;
}
i++;
}
System.out.println("All even? " + allEven); // true
}
}7. 统计满足条件的元素数量 (Count)
模板:counter++。
import java.util.ArrayList;
public class CountProperty {
public static void main(String[] args) {
ArrayList<String> words = new ArrayList<String>();
words.add("apple");
words.add("ant");
words.add("banana");
words.add("axe");
int countA = 0;
for (int i = 0; i < words.size(); i++) {
if (words.get(i).startsWith("a")) {
countA++;
}
}
System.out.println("Count startsWith a: " + countA); // 3
}
}8. 访问所有相邻元素对 (Consecutive Pairs)
最关键:循环到 size - 1,否则 i+1 越界。
import java.util.ArrayList;
public class ConsecutivePairs {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(5);
nums.add(1);
nums.add(7);
for (int i = 0; i < nums.size() - 1; i++) {
int a = nums.get(i);
int b = nums.get(i + 1);
System.out.println("Pair: " + a + ", " + b);
}
}
}9. 判断是否存在重复元素 (Duplicates)
经典嵌套循环:用 j = i + 1 避免重复比较和自比。
import java.util.ArrayList;
public class HasDuplicates {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(2);
nums.add(5);
nums.add(2);
nums.add(9);
boolean hasDup = false;
for (int i = 0; i < nums.size() && !hasDup; i++) {
for (int j = i + 1; j < nums.size() && !hasDup; j++) {
if (nums.get(i).equals(nums.get(j))) {
hasDup = true;
}
}
}
System.out.println("Has duplicate? " + hasDup); // true
}
}10. 左移 / 右移 / 旋转 (Shift / Rotate)
注意:这里演示的是 旋转 rotate(首/尾会“绕回去”)。
A) 向左旋转一位(第 0 个去末尾)
import java.util.ArrayList;
public class RotateLeftByOne {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(5);
nums.add(1);
nums.add(7);
int first = nums.get(0);
for (int i = 0; i < nums.size() - 1; i++) {
nums.set(i, nums.get(i + 1));
}
nums.set(nums.size() - 1, first);
System.out.println(nums); // [5, 1, 7, 3]
}
}B) 向右旋转一位(最后一个去开头)
import java.util.ArrayList;
public class RotateRightByOne {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(5);
nums.add(1);
nums.add(7);
int last = nums.get(nums.size() - 1);
for (int i = nums.size() - 1; i >= 1; i--) {
nums.set(i, nums.get(i - 1));
}
nums.set(0, last);
System.out.println(nums); // [7, 3, 5, 1]
}
}11. 反转列表顺序 (Reverse)
原地交换:只循环到一半,左右对称交换。
import java.util.ArrayList;
public class ReverseArrayList {
public static void main(String[] args) {
ArrayList<String> words = new ArrayList<String>();
words.add("A");
words.add("B");
words.add("C");
words.add("D");
for (int i = 0; i < words.size() / 2; i++) {
int j = words.size() - 1 - i;
String temp = words.get(i);
words.set(i, words.get(j));
words.set(j, temp);
}
System.out.println(words); // [D, C, B, A]
}
}✅ 小结:考试怎么套模板?
- 需要“找一个” → At Least One(布尔 found)
- 需要“全都” → All(布尔 all)
- 需要“数多少个” → Count(counter++)
- 需要“删一堆” → 倒序 for 删除
- 需要“相邻关系” → 循环到
size-1 - 需要“旋转/移动” → 先暂存 first/last,再用 set 覆盖