【总结】Java数据结构与刷题常用方法(持续更新中)

更多算法题的题解见:算法刷题题解汇总(持续更新中)

Java数据结构与刷题常用方法

输入和输出

Scanner scanner = new Scanner(System.in); // 创建一个Scanner对象,用于从标准输入读取

  1. Scanner 类是 Java 中的一个用于文本扫描的实用程序,它可以从各种输入源(如文件、输入流、字符串等)中读取文本。以下是 Scanner 类的一些常用方法:
  2. Scanner(InputStream source): 构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
  3. Scanner(File source): 构造一个新的 Scanner,它生成的值是从指定的文件扫描的。
  4. Scanner(String source): 构造一个新的 Scanner,它生成的值是从指定的字符串扫描的。
  5. boolean hasNext(): 如果此扫描器的输入中有另一个token,则返回true。
  6. boolean hasNext(String pattern): 如果下一个token匹配指定的正则表达式,则返回 true。
  7. String next(): 查找并返回来自此扫描器的下一个完整token。
  8. String next(String pattern): 如果下一个token与指定的正则表达式匹配,则返回下一个token。
  9. int nextInt(): 将输入的下一个标记扫描为 int 值。
  10. long nextLong(): 将输入的下一个标记扫描为 long 值。
  11. float nextFloat(): 将输入的下一个标记扫描为 float 值。
  12. double nextDouble(): 将输入的下一个标记扫描为 double 值。
  13. String nextLine(): 此方法返回输入的下一行文本。
  14. Scanner useDelimiter(String pattern): 设置此扫描器使用的分隔模式。
  15. void close(): 关闭此扫描器。
  16. 以下是一个使用 Scanner 类的基本示例:
import java.util.Scanner;
public class ScannerExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建一个Scanner对象,用于从标准输入读取
        System.out.print("Enter your name: ");
        String name = scanner.next(); // 读取下一个字符串
        System.out.print("Enter your age: ");
        int age = scanner.nextInt(); // 读取下一个整数
        System.out.print("Enter your height: ");
        double height = scanner.nextDouble(); // 读取下一个double值
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.println("Height: " + height);
        scanner.close(); // 关闭scanner
    }
}

在使用 Scanner 时,需要注意的是,如果输入的类型与期望的类型不匹配,将会抛出 InputMismatchException。此外,在使用完 Scanner 后应该调用 close() 方法来关闭它,以释放与其关联的系统资源。

常用方法

数组

获取长度 arr.length

3X4的表格:3行4列

二维数组int[[]][][] grid的行和列:

  • 行:grid.length
  • 列:grid[0].length

列表List

获取长度 list.size();
获取最大值 :

List list = Arrays.asList(1, 2, 3, 4, 5);
Integer max = Collections.max(list);

判断是否存在某些元素contains()

List<String> wordDict

wordDictSet.contains("word")
clear()方法(力扣78)

List.clear()清空列表中所有元素

String

String s
**s.charAt(i):**返回字符串s中索引为i的位置上的字符

s.substring(j, i) :是String类的一个方法,它返回字符串s的一个子字符串。这个子字符串从索引j开始,到索引i - 1结束(不包括索引i位置的字符)

  • j:子字符串的起始索引(i 包含在子字符串中)。
  • i:子字符串的结束索引(j 不包含在子字符串中)。

char[] charArray = s.toCharArray():将字符串s转换为一个字符数组,并将其赋值给charArray变量。注意空字符也会存入

String s = "Hello World";
char[] charArray = s.toCharArray();

// 此时,charArray 的内容为:{'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'}
char字符转换成String方法:
方法1:使用StringvalueOf方法
char ch = 'a';
String str = String.valueOf(ch);
方法2:使用Character类的toString方法
char ch = 'a';
String str = Character.toString(ch);
方法3:使用String构造函数
char ch = 'a';
String str = new String(new char[]{ch});
// 或者直接
String str = new String(new char[]{ch});
方法4:直接与空字符串相加

在Java中,如果你将char类型与一个字符串相加,char会被自动转换成String

char ch = 'a';
String str = "" + ch;

通常情况下,方法1和方法4是最常用和最简洁的。方法1非常明确地表示了转换的意图,而方法3则利用了Java的自动装箱和字符串连接特性,使代码更加简洁。根据具体的使用场景和编码风格,你可以选择最适合的方法。

StringBuffer与StringBuilder

``StringBufferStringBuilder` 是 Java 中的两个类,它们都用于处理可变的字符序列,但它们之间有一些关键的区别。

  1. 线程安全性
    • StringBuffer 是线程安全的。这意味着在多线程环境中,多个线程可以同时访问和修改同一个 StringBuffer 实例,而不会出现线程安全问题。
    • StringBuilder 不是线程安全的。在多线程环境中,如果多个线程同时访问和修改同一个 StringBuilder 实例,可能会出现线程安全问题。
  2. 性能
    • StringBuilder 通常比 StringBuffer 更快,因为它不是线程安全的。在单线程环境中,使用 StringBuilder 可以获得更好的性能。
    • StringBuffer 在多线程环境中是安全的,但这也意味着它的性能可能会比 StringBuilder 差一些。
  3. 使用场景
    • 如果你的应用程序需要处理多线程环境,并且需要保证字符串操作的线程安全,你应该使用 StringBuffer
    • 如果你的应用程序是单线程的,或者你可以确保在单线程环境中使用,你应该使用 StringBuilder,因为它通常更高效。
  4. 内存分配
    • StringBufferStringBuilder 都实现了 AbstractStringBuilder 类,它们内部都使用了一个字符数组(char[])来存储字符序列。
    • StringBufferStringBuilder 需要扩大其内部数组以容纳更多的字符时,它会创建一个新的字符数组,并将旧的字符数组复制到新数组中。这称为“数组复制”。
  5. 方法签名
    • StringBuffer 类提供了一些方法,这些方法以 Synchronized 开头,表示它们是线程安全的。
    • StringBuilder 类的方法没有 Synchronized 前缀,因此它们不是线程安全的。
      在大多数情况下,如果你不需要线程安全,应该优先选择 StringBuilder,因为它通常更快。只有在确实需要线程安全的情况下,才应该使用 StringBuffer

`

new StringBuffer() 是Java中创建一个StringBuffer类实例的语句。StringBuffer 是一个可变的字符序列,它提供了一个线程安全的文本缓冲区,用于存储和操作字符串。

以下是 StringBuffer 的一些常用方法:

  1. 构造方法
    • StringBuffer(): 创建一个空的字符串缓冲区,初始容量为 16 个字符。
    • StringBuffer(CharSequence seq): 创建一个包含指定字符序列的字符串缓冲区。
    • StringBuffer(int capacity): 创建一个空的字符串缓冲区,初始容量由参数指定。
  2. 追加方法
    • append(String str): 将指定的字符串追加到此字符序列。
    • append(char c): 将指定的字符追加到此字符序列。
    • append(int i): 将指定的整数值追加到此字符序列。
  3. 插入方法
    • insert(int offset, String str): 将字符串插入此字符序列中。
    • insert(int offset, char c): 将字符插入此字符序列中。
    • insert(int offset, boolean b): 将布尔值转换为字符串后插入此字符序列中。
  4. 删除方法
    • delete(int start, int end): 删除指定位置之间的字符。(左闭右开,含start,不含end)
    • deleteCharAt(int index): 删除指定位置的字符。
  5. 替换方法
    • replace(int start, int end, String str): 将指定位置的字符替换为指定的字符串。
  6. 反转方法
    • reverse(): 将此字符序列中的字符顺序反转
  7. 其他方法
    • length(): 返回长度(字符数)。
    • charAt(int index): 返回指定索引处的字符。
    • substring(int start, int end): 返回一个新字符串,它是此序列的一个子序列。
    • ensureCapacity(int minimumCapacity): 确保容量至少等于指定的最小值。
    • setLength(int newLength): 设置字符序列的长度。
  8. 转换为字符串
    • toString(): 返回此序列中数据的字符串表示形式。

以下是关于 StringBuffer 的几个关键点:

  1. 可变性:与 String 类不同,StringBuffer 是可变的,这意味着你可以修改 StringBuffer 的内容而不会创建一个新的对象。
  2. 线程安全StringBuffer 的所有公共方法都是同步的,这意味着它是线程安全的。在多线程环境中,多个线程可以安全地使用同一个 StringBuffer 实例。
  3. 性能:由于 StringBuffer 是可变的,对它的操作(如添加、删除字符)通常比使用 String 的操作更高效,因为 StringBuffer 不需要在每次修改时都创建一个新的字符串对象。
    下面是 StringBuffer 的一个简单示例:
StringBuffer stringBuffer = new StringBuffer("Hello");
stringBuffer.append(" World"); // 添加字符串到末尾
System.out.println(stringBuffer); // 输出 "Hello World"

在这个例子中,我们创建了一个 StringBuffer 实例,并使用 append 方法添加了一个字符串到它的末尾。
然而,从Java 5开始,StringBuilder 类被引入,它和 StringBuffer 类似,但是 StringBuilder 不是线程安全的。在单线程环境中,通常推荐使用 StringBuilder,因为它比 StringBuffer 更快,因为它不需要考虑线程同步的开销。除非你需要线程安全,否则应该优先使用 StringBuilder

需要注意的是:

StringBuffer.toString() 方法会生成一个独立的 String 对象,这个对象包含了 StringBuffer 当前持有的字符序列。

当你调用 toString() 方法时,它会创建并返回一个新的 String 实例,这个实例的内容与 StringBuffer 中的内容相同。这个新的 String 对象是 StringBuffer 内容的一个副本,因此对 StringBuffer 的后续修改不会影响这个 String 对象。

这意味着在做题时,尤其是回溯类题目,当一个满足条件的回答成立时,可以直接.toString()然后加入List的ans,而不需要向List类型的combine加入List<List>类型的ans时,需要ans.add(new ArrayList<>(combine))

Integer

Integer类中的最大值是Integer.MAX_VALUE,其值为2^31 - 1,即2147483647

Integer类中的最小值是Integer.MIN_VALUE,其值为-2^31,即-2147483648

将单个字符转换为数字的方法
使用字符的ASCII值

每个字符在ASCII表中都有一个对应的整数值。对于数字字符 ‘0’ 到 ‘9’,它们的ASCII值分别是48到57。你可以通过减去 ‘0’ 的ASCII值来将字符转换为相应的数字:

char ch = '5';
int num = ch - '0'; // 结果是5

这个方法只适用于数字字符。

使用Character类的方法

Java的Character类提供了getNumericValue(char ch)方法,这个方法可以用于获取字符的数值,如果字符是数字字符的话:

char ch = '5';
int num = Character.getNumericValue(ch); // 结果是5

如果ch不是数字字符,getNumericValue方法会返回-1或者其它非数字的对应整数值。

示例代码
public class CharToNumber {
    public static void main(String[] args) {
        char ch = '5';
        
        // 方法1: 使用ASCII值
        int num1 = ch - '0';
        System.out.println("Using ASCII value: " + num1);
        
        // 方法2: 使用Character类的方法
        int num2 = Character.getNumericValue(ch);
        System.out.println("Using Character.getNumericValue: " + num2);
    }
}
将String字符串转为int类型(常用Integer.valueOf(str)和 Integer.parseInt(s))
1. 使用基本数据类型的包装类
a. Integer.parseInt(String s)

将字符串转换为int类型:

String str = "123";
int num = Integer.parseInt(str);
b. Long.parseLong(String s)

将字符串转换为long类型:

String str = "123456789012345";
long num = Long.parseLong(str);
c. Float.parseFloat(String s)

将字符串转换为float类型:

String str = "123.45";
float num = Float.parseFloat(str);
d. Double.parseDouble(String s)

将字符串转换为double类型:

String str = "123.456789";
double num = Double.parseDouble(str);
2. 使用ValueOf方法

包装类的valueOf方法也可以将字符串转换为对应的数字类型:

String str = "123";
Integer num = Integer.valueOf(str);
3. 使用NumberFormat和DecimalFormat类

如果你需要处理更复杂的数字格式(例如,包含货币符号或千位分隔符),你可以使用NumberFormatDecimalFormat类:

import java.text.NumberFormat;
import java.text.ParseException;
String str = "1,234.56";
NumberFormat format = NumberFormat.getInstance();
Number number = format.parse(str);
double num = number.doubleValue();
注意事项
  • 当你使用上述方法时,如果字符串不能被解析为有效的数字,将会抛出NumberFormatException
  • 在解析前,确保字符串确实表示一个有效的数字,以避免运行时错误。
  • 对于非数字字符,你需要进行额外的处理或验证。
    下面是一个简单的例子,展示如何将字符串转换为数字,并处理可能的异常:
public class StringToNumber {
    public static void main(String[] args) {
        String str = "1234";
        try {
            int num = Integer.parseInt(str);
            System.out.println("The number is: " + num);
        } catch (NumberFormatException e) {
            System.out.println("The string does not contain a parsable integer.");
        }
    }
}

使用这些方法,你可以根据需要将字符串转换为不同的数字类型。

Character(一般直接用静态方法)

Character 类是 Java 中的一个包装类,用于对基本数据类型 char 的对象进行操作。它包含了许多用于处理字符的静态方法和实例方法。以下是一些常用的 Character 类方法:

静态方法:
  1. static boolean isLetter(char ch)
    • 确定指定的字符是否为字母。
  2. static boolean isDigit(char ch)
    • 确定指定的字符是否为数字。
  3. static boolean isWhitespace(char ch)
    • 确定指定的字符是否为空白字符。
  4. static boolean isUpperCase(char ch)
    • 确定指定的字符是否为大写字母。
  5. static boolean isLowerCase(char ch)
    • 确定指定的字符是否为小写字母。
  6. static char toUpperCase(char ch)
    • 使用取自 UnicodeData 文件的大小写映射信息将字符转换为大写。
  7. static char toLowerCase(char ch)
    • 使用取自 UnicodeData 文件的大小写映射信息将字符转换为小写。
  8. static int digit(char ch, int radix)
    • 确定字符在指定基数中的数值。
  9. static boolean isUpperCase(char ch)
    • 确定指定的字符是否为大写字母。
  10. static boolean isLowerCase(char ch)
    • 确定指定的字符是否为小写字母。
  11. static boolean isLetterOrDigit(char ch)
    • 确定指定的字符是否为字母或数字。
  12. static boolean isSpaceChar(char ch)
    • 确定指定的字符是否为 ISO-LATIN-1 空格字符。
实例方法:
  1. boolean isLetter()
    • 确定此字符是否为字母。
  2. boolean isDigit()
    • 确定此字符是否为数字。
  3. boolean isWhitespace()
    • 确定此字符是否为空白字符。
  4. boolean isUpperCase()
    • 确定此字符是否为大写字母。
  5. boolean isLowerCase()
    • 确定此字符是否为小写字母。
  6. char toUpperCase()
    • 将此 Character 对象中的值转换为大写。
  7. char toLowerCase()
    • 将此 Character 对象中的值转换为小写。
  8. int digit(int radix)
    • 在给定的基数中,将此 Character 对象中的值转换为整数。
  9. boolean isUpperCase()
    • 确定此字符是否为大写字母。
  10. boolean isLowerCase()
    • 确定此字符是否为小写字母。
  11. boolean isLetterOrDigit()
    • 确定此字符是否为字母或数字。
  12. boolean isSpaceChar()
    • 确定此字符是否为 ISO-LATIN-1 空格字符。
      这些方法在处理文本和字符时非常有用,可以帮助开发者执行各种字符检查和转换操作。

HashMap

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

在Java中,HashMap 是一个基于哈希表的映射接口的实现,它存储键值对。以下是 HashMap 的一些基本方法:

构造方法
  • HashMap(): 创建一个空的 HashMap
  • HashMap(int initialCapacity): 创建一个指定初始容量的空的 HashMap
  • HashMap(int initialCapacity, float loadFactor): 创建一个具有指定初始容量和负载因子的空的 HashMap
  • HashMap(Map<? extends K, ? extends V> m): 创建一个包含指定映射的 HashMap
基本操作
  • void clear(): 清除 HashMap 中的所有键值对。
  • boolean containsKey(Object key): 检查 HashMap 是否包含指定的键。
  • boolean containsValue(Object value): 检查 HashMap 是否包含一个指定的值。
  • boolean isEmpty(): 检查 HashMap 是否为空。
  • V get(Object key): 返回指定键所映射的值,如果映射不包含该键的映射,则返回 null
  • V put(K key, V value): 将指定的键值对插入到 HashMap 中。
  • V remove(Object key): 从 HashMap 中移除指定的键及其对应的值。
遍历操作
  • Set keySet(): 返回 HashMap所有key值Set 视图。

  • Collection values(): 返回 HashMap所有value值Collection 视图。

  • Set<Map.Entry<K, V>> entrySet(): 返回 HashMap所有键值对Set 视图。

    **注意:**视图与 HashMap 同步。任何对 HashMap 的修改(添加、删除键值对等)都会立即在视图中体现出来。同理,视图的任何更改(例如添加或删除操作)都会直接反映在原始的 HashMap

    entrySet()用法:

    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    public class Main {
        public static void main(String[] args) {
            // 创建一个HashMap实例
            HashMap<Integer, String> map = new HashMap<>();
            // 添加一些键值对
            map.put(1, "苹果");
            map.put(2, "香蕉");
            map.put(3, "橙子");    
        // 获取所有键值对
        Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
    
        // 遍历所有键值对
        for (Map.Entry<Integer, String> entry : entrySet) {
            // 获取键和值
            Integer key = entry.getKey();
            String value = entry.getValue();
            // 打印键值对
            System.out.println("键: " + key + ", 值: " + value);
        }
    }
    

    }

其他操作
  • int size(): 返回 HashMap 中的键值对数量。
  • void putAll(Map<? extends K, ? extends V> m): 将指定映射中的所有映射复制到此映射中。
  • V replace(K key, V value): 仅当指定键存在时,替换指定键的值。
  • boolean replace(K key, V oldValue, V newValue): 仅当指定键存在并且当前值等于旧值时,替换指定键的值。
    这些方法构成了 HashMap 的基本操作集,可以用来实现大多数键值对映射的需求。需要注意的是,由于 HashMap 允许一个键为 null,并且最多允许一个键为 null,还允许任意数量的值为 null,因此在使用这些方法时需要特别注意对 null 值的处理。

Math

在Java中,Math类提供了多种用于执行基本数学运算的方法。这些方法都是静态的,因此可以直接通过类名来调用,而无需创建Math类的实例。以下是一些常用的Math类方法:

基本数学运算
  • Math.abs(double a):返回a的绝对值。
  • Math.abs(int a):返回a的绝对值。
  • Math.max(double a, double b):返回ab中的最大值。
  • Math.max(int a, int b):返回ab中的最大值。
  • Math.min(double a, double b):返回ab中的最小值。
  • Math.min(int a, int b):返回ab中的最小值。
  • Math.sqrt(double a):返回a的平方根。
  • Math.cbrt(double a):返回a的立方根。
获取长度(length,length(),size())

在Java中,lengthlength() 都是用来获取“长度”的,但是它们的使用场景是不同的:

  1. length 属性:

    • 通常用于数组,用来获取数组的长度。

    • 适用于所有类型的数组(如 int[], double[], `` 等)。

    • 例如:

      int[] numbers = new int[10];
      int arrayLength = numbers.length; // 使用length属性获取数组长度
      
  2. length() 方法:

    • 专用于 String 类,用来获取字符串中的字符数量。

    • 例如:

      String myString = "Hello, World!";
      int stringLength = myString.length(); // 使用length()方法获取字符串长度
      

      以下是使用 lengthlength() 的具体情况:

      记住:String[ ]用.length,而String用length()

使用 length 的情况:
  • 处理基本类型数组或对象数组时。

  • 例如:

    char[] chars = {'a', 'b', 'c'};
    System.out.println(chars.length); // 输出:3
    
使用 length() 的情况:

-处理字符串时。

  • 例如:

    String text = "abcdef";
    System.out.println(text.length()); // 输出:6
    

    需要注意的是,Java中并没有直接提供获取集合(如 List, Set, Map 等)长度的 length 属性或 length() 方法。对于集合,你应该使用 size() 方法来获取其中元素的数量。例如:

List<String> list = new ArrayList<>();
list.add("Item 1");
list.add("Item 2");
System.out.println(list.size()); // 输出:2

总之,记住 length 是数组的一个属性,而 length()String 类的一个方法。

使用size()的情况

在Java中,除了数组和字符串之外,其他集合类型通常使用 size() 方法来获取它们包含的元素数量。以下是一些常见集合类型及其获取长度的方法:

  1. ArrayList, LinkedList, Vector (实现 List 接口):

    • 使用 size() 方法获取列表中的元素数量。

    • 例如:

      List<String> list = new ArrayList<>();
      list.add("Item 1");
      list.add("Item 2");
      int size = list.size(); // 获取列表长度
      
  2. HashSet, TreeSet, LinkedHashSet (实现 Set 接口):

    • 使用 size() 方法获取集合中的元素数量。

    • 例如:

      Set<String> set = new HashSet<>();
      set.add("Item 1");
      set.add("Item 2");
      int size = set.size(); // 获取集合长度
      
  3. HashMap, TreeMap, LinkedHashMap (实现 Map 接口):

    • 使用 size() 方法获取映射中的键值对数量。

    • 例如:

      Map<String, String> map = new HashMap<>();
      map.put("Key 1", "Value 1");
      map.put("Key 2", "Value 2");
      int size = map.size(); // 获取映射长度
      
  4. ArrayDeque, PriorityQueue (实现 Queue 接口):

    • 使用 size() 方法获取队列中的元素数量。

    • 例如:

      Queue<String> queue = new ArrayDeque<>();
      queue.add("Item 1");
      queue.add("Item 2");
      int size = queue.size(); // 获取队列长度
      
  5. ArrayBlockingQueue, LinkedBlockingQueue (实现 BlockingQueue 接口):

    • 使用 size() 方法获取阻塞队列中的元素数量。

    • 例如:

      BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(10);
      blockingQueue.add("Item 1");
      blockingQueue.add("Item 2");
      int size = blockingQueue.size(); // 获取阻塞队列长度
      
  6. Stack (实现 Vector 类):

    • 使用 size() 方法获取栈中的元素数量。

    • 例如:

      Stack<String> stack = new Stack<>();
      stack.push("Item 1");
      stack.push("Item 2");
      int size = stack.size(); // 获取栈长度
      

      这些方法返回的都是集合中的元素数量,它们适用于Java集合框架中的大多数集合类型。记住,对于数组,始终使用 length 属性;对于字符串,使用 length() 方法;而对于其他集合类型,使用 size() 方法。

三角函数
  • Math.sin(double a):返回a的正弦值(以弧度为单位)。
  • Math.cos(double a):返回a的余弦值(以弧度为单位)。
  • Math.tan(double a):返回a的正切值(以弧度为单位)。
反三角函数
  • Math.asin(double a):返回a的反正弦值(以弧度为单位)。
  • Math.acos(double a):返回a的反余弦值(以弧度为单位)。
  • Math.atan(double a):返回a的反正切值(以弧度为单位)。
指数和对数
  • Math.exp(double a):返回ea次幂。
  • Math.log(double a):返回a的自然对数(以e为底)。
  • Math.log10(double a):返回a的以10为底的对数。

幂运算

  • Math.pow(double a, double b):返回ab次幂。
四舍五入
  • Math.round(double a):返回a四舍五入后最接近的long类型整数。
  • Math.ceil(double a):返回大于或等于a的最小整数值。
  • Math.floor(double a):返回小于或等于a的最大整数值。
随机数
  • Math.random():返回一个大于等于0.0且小于1.0的伪随机double值。
其他
  • Math.PI:返回圆周率π的值。
  • Math.E:返回自然对数的底数e的值。
    这些方法涵盖了数学运算的许多方面,并且可以用于各种编程任务中。需要注意的是,三角函数和指数对数方法通常需要输入值以弧度为单位,如果使用的是角度,需要先将角度转换为弧度。

常用集合增加和移除元素的方法

在 Java 中,常用的集合类如 ListSetQueue 都有它们各自的方法来添加和移除元素。下面是一些常用的集合类及其增加和移除元素的方法:

List 接口
  • ArrayListLinkedListList 接口的两个常用实现。
添加元素:
  • add(E e):在列表的末尾添加元素。
  • add(int index, E element):在指定索引处添加元素。
移除元素:
  • remove(int index):移除指定索引处的元素。
  • remove(Object o):移除列表中首次出现的指定元素。
  • clear():移除列表中的所有元素。
Set 接口
  • HashSetLinkedHashSetTreeSetSet 接口的常用实现。
添加元素:
  • add(E e):如果指定的元素不存在于集合中,则添加它。
移除元素:
  • remove(Object o):如果存在,则移除指定的元素。
  • clear():移除集合中的所有元素。
Queue 接口
  • PriorityQueueLinkedList(也可以用作队列)是 Queue 接口的常用实现。
添加元素:
  • add(E e):添加元素,如果队列已满,抛出 IllegalStateException
  • offer(E e):添加元素,如果队列已满,返回 false
移除元素:
  • remove():移除队列头部的元素,如果队列为空,抛出 NoSuchElementException
  • poll():移除队列头部的元素,如果队列为空,返回 null
  • clear():对于某些实现,如 LinkedList,可以用来清空队列。
    下面是一个简单的示例,展示了如何使用这些方法:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
public class Main {
    public static void main(String[] args) {
        // List 示例
        List<String> arrayList = new ArrayList<>();
        arrayList.add("Apple");
        arrayList.add(1, "Banana");
        arrayList.remove(0); // 移除第一个元素
        arrayList.remove("Banana");
        // Set 示例
        Set<String> hashSet = new HashSet<>();
        hashSet.add("Apple");
        hashSet.add("Banana");
        hashSet.remove("Apple");
        hashSet.clear(); // 清空集合
        // Queue 示例
        Queue<String> queue = new LinkedList<>();
        queue.add("Apple");
        queue.offer("Banana");
        queue.remove(); // 移除并返回队列头部元素
        queue.poll(); // 移除并返回队列头部元素,如果队列为空,返回 null
        queue.clear(); // 清空队列
    }
}

这些是 Java 集合框架中添加和移除元素的基本方法。每个集合类可能还有其他特定于其实现的方法。在使用这些方法时,应该注意它们的返回类型和可能抛出的异常。

此外还有StringBufferStringBuilder,以及 Queue 接口的其他一些方法:

StringBuffer 和 StringBuilder

这两个类用于构建可变的字符串序列。StringBuilder 是非线程安全的,因此在单线程环境中通常更受欢迎,因为它比 StringBuffer 更快。StringBuffer 是线程安全的,因此适用于多线程环境。

添加元素:
  • append(String str):将指定的字符串追加到序列的末尾。
  • append(char c):将指定的字符追加到序列的末尾。
  • insert(int offset, String str):将字符串插入到指定位置。
移除元素:
  • delete(int start, int end):移除序列中从 start 到 end(不包括 end)的字符。
  • deleteCharAt(int index):移除指定位置的字符。
  • setLength(int newLength):设置序列的长度,如果新长度小于当前长度,则会截断序列。
    示例:
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" World");
sb.insert(5, ", ");
sb.delete(0, 6); // 删除 "Hello, "
sb.deleteCharAt(sb.length() - 1); // 删除最后一个字符(空格)

常用集合获取长度的方法

在Java中,不同的集合类型有不同的方法来获取它们的长度或大小。以下是一些常用集合及其获取长度的方法:

1. 数组

数组有一个 length 属性来获取其长度。

int[] numbers = new int[10];
int length = numbers.length; // 获取数组的长度
2. List

List 接口有一个 size() 方法来获取列表的长度。

List<String> list = new ArrayList<>();
int size = list.size(); // 获取列表的长度
3. Set

Set 接口同样有一个 size() 方法来获取集合的长度。

Set<String> set = new HashSet<>();
int size = set.size(); // 获取集合的长度
4. Map

Map 接口有一个 size() 方法来获取键值对的数量。

Map<String, Integer> map = new HashMap<>();
int size = map.size(); // 获取Map的大小(键值对的数量)
5. Queue

Queue 接口也提供了 size() 方法来获取队列的长度。

Queue<String> queue = new LinkedList<>();
int size = queue.size(); // 获取队列的长度
6. Deque

Deque(双端队列)接口也有 size() 方法来获取队列的长度。

Deque<String> deque = new ArrayDeque<>();
int size = deque.size(); // 获取双端队列的长度
7. 其他集合类型

其他集合类型如 Stack、PriorityQueue 等,它们通常也有 size() 方法来获取集合的长度。
这些 size() 方法都是快速操作,通常具有 O(1) 的时间复杂度,因为集合内部维护了元素数量的计数。当你在使用这些集合时,应该使用这些方法来获取集合的长度或大小。

集合常用方法

Arrays静态方法
Arrays.fill()

在Java中,Arrays.fill() ,用于将指定的值分配给数组中所有或部分元素。这对于初始化数组元素特别有用,可以将整个数组或数组的一部分设置为相同的值。
以下是 Arrays.fill() 方法的一些常见用法:

填充整个数组
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        int[] array = new int[5];
        Arrays.fill(array, 10); // 将数组所有元素设置为10
        System.out.println(Arrays.toString(array)); // 输出 [10, 10, 10, 10, 10]
    }
}
填充数组的一部分

fill() 方法也可以用来填充数组的一个范围,需要指定起始索引(包括)和结束索引(不包括)。

import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        int[] array = new int[5];
        Arrays.fill(array, 0, 3, 10); // 将数组索引从0到2的元素设置为10
        System.out.println(Arrays.toString(array)); // 输出 [10, 10, 10, 0, 0]
    }
}
注意事项
  • 使用 fill() 方法时,指定的值必须是数组元素类型的值。
  • 如果指定的范围超出了数组的实际范围,会抛出 ArrayIndexOutOfBoundsException
  • fill() 方法会改变原数组,它不会创建一个新数组。
    这个方法在处理数组时非常有用,尤其是在需要将数组初始化为默认值或清除数据时。
Collections

Collections.reverse():

用于反转指定列表中的元素顺序。

  • 它接受一个 List 类型的参数。
  • 它会直接在传入的列表上进行操作,而不是返回一个新的列表。
  • 它不能用于 SetMap 或其他类型的集合,因为这些集合不保证元素的顺序,或者不支持顺序修改。

如果你尝试在一个不支持 List 接口的集合上使用 Collections.reverse 方法,编译器将会报错,因为这个方法要求传入的参数必须是 List 类型。

Collections.reverse() 可以反转 ArrayDequeLinkedLList中元素的顺序

栈和队列(先看总结)

在Java中,栈(Stack)和队列(Queue)都是通过集合框架(Collections Framework)中的接口和类来实现的。这些接口和类位于java.util包中。

组合:(注意ArrayDeque可以存地址但是不能存null,遇到需要存null值时统一用LinkedLList)

栈:push和poll、push和pop组合都可以实现栈(先进后出,后进先出)

队列:add和poll组合实现队列(先进先出,后进后出)

peek()获得并返回最左侧元素但不删除元素,即查看最左侧元素,用在以上两个组合中可以分别查看栈顶和队列头部的元素

Collections.reverse() 可以反转 ArrayDequeLinkedLList中元素的顺序

总结:

都可以用ArrayDeque和LinkedList来实现,其中有专门为队列写的Queue接口,没有为栈写的接口,栈可以用Queue的实现类进行实现。

  • 注意ArrayDeque可以存地址但是不能存null,遇到需要存null值时统一用LinkedLList
  • Queue是父类,子类有Deque,Deque的子类有ArrayDeque, LinkedList,且 LinkedList父类有List, Deque
  • Deque、ArrayDeque、LinkedList有push()——元素加在最左侧、pop()——弹出最左侧的元素、offer()——元素加在最右侧、poll()——弹出最左侧的元素
  • 但是Queue无push()、pop()
  • List的remove与Queue的remove方法不同,Queue和Deque的remove()默认移除最左侧元素,remove(x)表示移除Queue中值为x的元素,即移除元素x;List的remove(x)必修传入参数,表示移除索引为x的元素。

对于列表list1: [1,2,3,4]

  • push(x): 将元素x加在list1最左侧,即开头
  • pop(): 弹出最左侧的元素。push和pop两个组合可以实现栈:先入后出,后入先出,因为先push会被后push的压到右边,新压入的元素在最左侧
  • offer(x):将元素x加在list1最右侧,即末尾,
  • poll():与pop的效果一样, 弹出最左侧的元素。两个组合实现队列:先入先出,后入后出,因为先offer入队会被后offer入队的压到左边,新压入的元素在最右侧,之前压入的元素在最左侧,而poll弹出最左侧元素,先入队列的被弹出了。
  • **.add():将元素x加在list1最右侧(**对栈和队列都是加在最右侧)
  • **.isEmpty()**判断是否为空,
  • 对于Duque和queue,remove()是移除最左侧的元素,remove(x)是指移除数据结构中的x元素,而不是索引为x的元素。
  • **但是有对于List,包括LinkedList,remove(x),remove中必须加参数,参数x代表索引,即Index为x的元素,与上一行不同。**ps:示例代码中:Queue queue = new LinkedList<>();queue的remove中的x为元素不是索引是因为父类是Queue,只能调用LinkedList实现的父类的Queue的方法,如果改为LinkedList queue = new LinkedList<>();此时remove()中必须要有参数,且参数为元素位置。
  • 注意参数列表,index则为所以,o则为元素。
  • peek()获得最左侧元素但不删除元素,即查看最左侧元素,由于以上两个组合栈顶和队列头部的元素都在最左侧,所以peek()可以查看栈顶和队列头部元素,但需要时push和pop组合,offer和poll组合才行
  • getLast()方法返回 ArrayDeque 和LinkedList的最右侧的元素
  • getFirst() 方法返回 ArrayDeque 的LinkedList最左侧的元素
  • removeLast() 方法移除并返回 最右侧的元素。
  • removeFirst() 方法移除并返回 最左侧的元素。
  • Collections.reverse()可反转集合中的元素顺序

需要注意的是:ArrayDeque和LinkedList拥有以上4个方法,但是以这种方式定义队列:Queue queue = new LinkedList<>(); Queue没有定义push和pop方法,所以不能使用。

以下是栈和队列的分别解释

栈(Stack)

Java并没有提供一个专门的Stack接口,而是使用Deque(双端队列)接口及其实现类来模拟栈的行为。Deque接口提供了栈的所有功能,包括push(入栈)和pop(出栈)操作,以及peek(查看栈顶元素)等。
以下是一些常用的实现Deque接口的类:

  • ArrayDeque:基于可变数组的实现,可以作为栈使用。
  • LinkedList:基于双向链表的实现,也可以作为栈使用。
    例如,使用ArrayDeque作为栈:
import java.util.ArrayDeque;
public class StackExample {
    public static void main(String[] args) {
        ArrayDeque<Integer> stack = new ArrayDeque<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println(stack.pop()); // 输出 3
        System.out.println(stack.pop()); // 输出 2
        System.out.println(stack.pop()); // 输出 1
    }
}
队列(Queue)

Java提供了Queue接口,用于表示队列数据结构。Queue接口扩展了Collection接口,并提供了特定的队列操作,如offer(入队)、poll(出队)、peek(查看队列头部元素)等。
以下是一些常用的实现Queue接口的类:

  • LinkedList:基于双向链表的实现,可以作为队列使用。
  • PriorityQueue:基于优先级堆的无界优先队列。
  • ArrayDeque:基于可变数组的实现,也可以作为队列使用。
    例如,使用LinkedList作为队列:
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.poll()); // 输出 1
        System.out.println(queue.poll()); // 输出 2
        System.out.println(queue.poll()); // 输出 3
    }
}

在Java的集合框架中,Deque接口同时实现了Queue接口和Stack的功能,因此它可以用来同时实现栈和队列的操作。

测试代码

import java.util.*;

public class t1 {
    public static void main(String[] args) {
        //List<Integer> L1 = new ArrayList<>();
        ArrayDeque<Integer> stack = new ArrayDeque<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        System.out.println(stack.toString());

        Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.remove(3));

        System.out.println(queue.toString());
        System.out.println(queue.poll()); // 输出 1
        System.out.println(queue.poll()); // 输出 2
        System.out.println(queue.poll()); // 输出 3


    }

}
ArrayDeque(实现队列和栈)
实现栈

ArrayDeque 类也可以作为栈使用,它提供了 pushpop 方法来模拟栈的行为,其中 push 方法用于将元素压入栈顶,而 pop 方法用于从栈顶移除元素。
以下是这两个方法的详细描述:

  • push(E e):将元素 e 压入栈顶,即双端队列的前端。如果双端队列可以容纳更多的元素,则返回 true(实际上 push 方法不会返回任何值,因为它是 addFirst 方法的别名)。
  • pop():从栈顶移除元素,即从双端队列的前端移除并返回第一个元素。如果双端队列为空,则抛出 NoSuchElementException 异常。
    下面是这两个方法的使用示例:
import java.util.ArrayDeque;
public class ArrayDequeAsStackExample {
    public static void main(String[] args) {
        ArrayDeque<Integer> stack = new ArrayDeque<>();
        // 将元素压入栈
        stack.push(10);
        stack.push(20);
        stack.push(30);
        // 从栈顶移除元素
        System.out.println(stack.pop());  // 输出 30
        System.out.println(stack.pop());  // 输出 20
        // 查看栈顶元素,但不移除它
        System.out.println(stack.peek()); // 输出 10
        // 再次从栈顶移除元素
        System.out.println(stack.pop());  // 输出 10
    }
}

如果栈为空,调用 poppeek 将分别抛出 NoSuchElementException 或返回 null

实现队列

ArrayDeque 类还提供了 addpoll 方法,这些方法也可以用于队列操作。以下是这两个方法的详细描述:

  • add(E e):将指定的元素添加到双端队列的末尾。如果双端队列可以容纳更多的元素,则返回 true,否则抛出 IllegalStateException。在 ArrayDeque 的实现中,除非达到其容量限制,否则总是返回 true
  • poll():检索并移除双端队列的头部元素,即第一个元素。如果双端队列为空,则返回 null
    下面是这两个方法的使用示例:
import java.util.ArrayDeque;
public class ArrayDequeAsQueueExample {
    public static void main(String[] args) {
        ArrayDeque<Integer> queue = new ArrayDeque<>();
        // 将元素添加到队列的末尾
        queue.add(10);
        queue.add(20);
        queue.add(30);
        // 从队列的头部移除元素
        System.out.println(queue.poll());  // 输出 10
        System.out.println(queue.poll());  // 输出 20
        // 查看队列的头部元素,但不移除它
        System.out.println(queue.peek()); // 输出 30 或 null 如果队列为空
        // 再次从队列的头部移除元素
        System.out.println(queue.poll());  // 输出 30
        // 尝试从空队列中移除元素
        System.out.println(queue.poll());  // 输出 null
    }
}

如果队列为空,调用 pollpeek 将分别返回 null 或返回 null。需要注意的是,与 add 方法不同,offer 方法在添加元素时如果队列已满,则返回 false 而不是抛出异常。

其他方法

ArrayDeque 是 Java 中的一个双端队列实现,它可以用作栈和队列。以下是 ArrayDeque 的一些常用方法:

构造方法

  • ArrayDeque():创建一个空的双端队列。
  • ArrayDeque(Collection<? extends E> c):创建一个包含指定集合的元素的双端队列。

添加元素

  • addFirst(E e):在双端队列的前端插入元素。
  • addLast(E e):在双端队列的末尾添加元素,等效于 add(E e)
  • offerFirst(E e):在双端队列的前端插入元素,如果双端队列可以容纳,则返回 true
  • offerLast(E e):在双端队列的末尾添加元素,如果双端队列可以容纳,则返回 true

删除元素

  • removeFirst():移除并返回双端队列的第一个元素。
  • removeLast():移除并返回双端队列的最后一个元素。
  • pollFirst():获取并移除双端队列的第一个元素,如果双端队列为空,则返回 null
  • pollLast():获取并移除双端队列的最后一个元素,如果双端队列为空,则返回 null
  • remove():移除第一个元素,等效于 removeFirst()
  • poll():获取并移除第一个元素,等效于 pollFirst()

查看元素

  • getFirst():返回双端队列的第一个元素。
  • getLast():返回双端队列的最后一个元素。
  • peekFirst():**获取最左边的元素,**获取但不移除双端队列的第一个元素,如果双端队列为空,则返回 null
  • peekLast():**获取最右边的元素,**获取但不移除双端队列的最后一个元素,如果双端队列为空,则返回 null
  • peek():**获取最左边的元素,**但不移除第一个元素,等效于 peekFirst()

其他方法

  • size():返回双端队列中的元素数量。
  • isEmpty():如果双端队列为空,则返回 true
  • clear():清空双端队列。
  • contains(Object o):如果双端队列包含指定的元素,则返回 true
  • iterator():返回此双端队列的迭代器。
  • descendingIterator():返回此双端队列的逆序迭代器。
    使用 ArrayDeque 时需要注意,它不是线程安全的,如果多个线程同时访问一个 ArrayDeque 实例,并且至少有一个线程修改了该结构,则必须保持外部同步。通常可以使用 Collections.synchronizedDeque 方法来包装 ArrayDeque 以实现同步。
Stack类

在Java中,Stack 类是 java.util 包中的一个类,它实现了标准的后进先出(LIFO)栈数据结构。以下是 Stack 类的一些基本操作:

创建一个 Stack
Stack<Integer> stack = new Stack<>();
基本操作
  • push(E item): 将元素压入栈顶。
  • pop(): 移除栈顶元素,并返回该元素。
  • peek(): 返回栈顶元素,但不移除它。
  • empty(): 检查栈是否为空。
  • search(Object o): 返回对象在栈中的位置,从1开始计数,如果对象不在栈中,则返回-1。
示例

以下是如何使用 Stack 类的示例:

import java.util.Stack;
public class StackExample {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        // 将元素压入栈
        stack.push(10);
        stack.push(20);
        stack.push(30);
        // 查看栈顶元素
        System.out.println("栈顶元素: " + stack.peek()); // 输出: 30
        // 移除栈顶元素
        System.out.println("移除的元素: " + stack.pop()); // 输出: 30
        // 再次查看栈顶元素
        System.out.println("新的栈顶元素: " + stack.peek()); // 输出: 20
        // 检查栈是否为空
        System.out.println("栈是否为空: " + stack.isEmpty()); // 输出: false
        // 查找元素在栈中的位置
        System.out.println("元素20的位置: " + stack.search(20)); // 输出: 1
        System.out.println("元素10的位置: " + stack.search(10)); // 输出: 2
        System.out.println("元素40的位置: " + stack.search(40)); // 输出: -1 (元素不在栈中)
    }
}

虽然 Stack 类在Java中仍然可用,但是基于早期Java集合框架的。现代Java代码更倾向于使用 Deque 接口及其实现,如 ArrayDeque,因为 ArrayDeque 提供了更好的性能(通常更快的操作和更少的内存使用)。示例:

import java.util.ArrayDeque;
import java.util.Deque;
public class ArrayDequeAsStackExample {
    public static void main(String[] args) {
        Deque<Integer> stack = new ArrayDeque<>();
        // 将元素压入栈
        stack.push(10);
        stack.push(20);
        stack.push(30);
        // 查看栈顶元素
        System.out.println("栈顶元素: " + stack.peek()); // 输出: 30
        // 移除栈顶元素
        System.out.println("移除的元素: " + stack.pop()); // 输出: 30
        // 再次查看栈顶元素
        System.out.println("新的栈顶元素: " + stack.peek()); // 输出: 20
        // 检查栈是否为空
        System.out.println("栈是否为空: " + stack.isEmpty()); // 输出: false
    }
}

编程细节

Java函数传入参数是否改变

在Java中,要想在方法内部改变外部变量的值,你需要理解Java的参数传递机制。Java总是按值传递参数,这意味着传递给方法的是值的一个副本。对于基本数据类型(如int、float等),这个副本就是数据值本身;对于对象(包括数组),这个副本是对象引用的一个拷贝。

如何改变外部变量的值
  1. 修改对象的状态:当你传递一个对象(包括数组)到一个方法时,虽然传递的是引用的副本,但这个副本和原始引用指向的是同一个对象。因此,如果方法内部改变了对象的状态(例如,修改数组的内容或更改对象的字段),那么这些变化对调用者是可见的。

    void changeObjectState(MyObject obj) {
        obj.setState(42); // 改变对象的状态
    }
    
  2. 使用返回值:如果需要改变基本数据类型的外部变量,可以通过方法返回值来实现。

    int changeValue(int value) {
        return value + 1; // 返回修改后的值
    }
    
如何只改变副本的值而不改变外部的值
  1. 修改参数副本:对于基本数据类型,如果你只是在方法内部修改参数的副本,那么原始变量的值不会改变。

    void changeLocalCopy(int value) {
        value = 42; // 只改变本地副本的值
    }
    
  2. 重新赋值引用:如果你在方法内部重新赋值对象引用,那么这个改变只在方法内部有效,不会影响原始引用。

    void changeReference(MyObject obj) {
        obj = new MyObject(); // 重新赋值引用,只影响本地副本
    }
    

    总结来说,如果你想要在方法内部改变外部变量的值:

  • 对于基本数据类型,使用返回值。

  • 对于对象,直接修改对象的状态。
    如果你不想要改变外部变量的值:

  • 对于基本数据类型,只需在方法内部操作参数的副本。

  • 对于对象,避免重新赋值引用,只修改对象的状态。

    例子:力扣189

    方法一

   class Solution {
       public void rotate(int[] nums, int k) {
           int len = nums.length;
           int[] temp = new int[len];
           for (int i = 0; i < len; i++) {
               temp[(i+k)%len] = nums[i];
           }
           **System.arraycopy(temp,0,nums,0,len);//这里不能写nums = temp;**
      }
   }
原因:

​ 在Java中,数组是对象,而对象是通过引用传递的。当你执行 nums = temp; 时,是在改变 nums 引用的指向,让它指向了 temp 所指向的数组。然而,这个改变只在 rotate 方法的局部作用域内有效,它并不会影响到调用 rotate 方法的代码中的 nums 数组。为Java的方法参数传递是按值传递的,当你传递一个数组(或其他对象)到一个方法时,你实际上传递的是这个数组引用的一个副本。在这个方法内部,nums 和 temp 都是这个引用副本的别名。 nums = temp; 时,你只是改变了这个副本指向的对象,并没有改变原始引用指向的对象。 而 System.arraycopy(temp, 0, nums, 0, len); 是不同的,它直接操作内存,temp 数组中的内容复制到 nums 数组中,这样 nums 数组的内容就改变了,这个改变是对调用者可见的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值