力扣收获
内容
三元运算符
1 | 三元运算符(`l1 != null ? l1.val : 0`)相当于 |
以下是关于链表的详细解答,涵盖你提到的所有问题:
链表
1. 如何新建一个链表
在 Java 中,链表是通过定义一个节点类(ListNode)来实现的。每个节点包含数据域和指针域。
定义链表节点
1 | class ListNode { |
创建链表
通过创建多个节点并链接它们来构建链表:1
2
3
4
5
6
7
8
9
10// 创建节点
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
// 链接节点
node1.next = node2;
node2.next = node3;
// node1 -> node2 -> node3 -> null
2. 使用指针指向链表头节点
在链表中,通常使用一个指针(引用)来指向链表的头节点,以便操作链表。
1 | ListNode head = node1; // head 指向链表的头节点 |
3. 如何通过指针给链表数据域注入数据
可以通过指针访问链表节点的数据域并修改其值。
1 | head.val = 10; // 修改头节点的值 |
4. 如何遍历注入数据
遍历链表时,可以通过指针逐个访问节点并修改数据域。
示例:遍历链表并修改每个节点的值
1 | ListNode current = head; // 定义指针 current,初始指向头节点 |
5. 返回一个链表所有数据,怎么返回
可以通过遍历链表,将每个节点的数据域存储到一个列表(如 List)中,然后返回该列表。
示例:返回链表的所有数据
1 | import java.util.ArrayList; |
6. Java 中链表的特点
Java 中的链表具有以下特点:
(1)动态大小
- 链表的大小可以动态增长或缩小,不需要预先分配固定大小的内存。
(2)插入和删除效率高
- 在链表中插入或删除节点的时间复杂度为 O(1)(如果已知插入/删除位置)。
- 相比于数组,链表在中间插入或删除数据时不需要移动其他元素。
(3)随机访问效率低
- 链表不支持随机访问,访问第
n个节点需要从头节点开始遍历,时间复杂度为 O(n)。
(4)内存开销
- 每个节点除了存储数据外,还需要额外的空间存储指针(引用),因此链表的内存开销比数组大。
(5)实现方式
- Java 提供了内置的链表实现:
java.util.LinkedList。 LinkedList是一个双向链表,支持在头部和尾部高效插入和删除数据。
(6)适用场景
- 需要频繁插入和删除数据的场景。
- 数据量不确定或动态变化的场景。
- 不需要频繁随机访问数据的场景。
完整示例代码
以下是一个完整的 Java 示例,演示如何创建链表、遍历链表、修改数据并返回链表的所有数据:
1 | class ListNode { |
总结
- 新建链表:通过定义节点类并链接节点。
- 指针操作:使用指针(引用)指向链表头节点,并通过指针操作链表。
- 遍历链表:通过循环逐个访问节点。
- 返回链表数据:将链表数据存储到列表并返回。
- 链表特点:动态大小、插入删除效率高、随机访问效率低。
数组
以下是正确的 for 循环写法:
1. 完整初始化
复制
1 | for (int i = 0; i < nums.length; i++) { |
2. 省略初始化(不推荐)
如果循环变量已经在外部定义,可以省略初始化部分,但必须保留分号:
复制
1 | int i = 0; |
3. 省略所有部分(无限循环)
如果省略所有部分,for 循环将变成一个无限循环:
复制
1 | for (;;) { |
4. 遍历数组
使用
for循环或for-each循环遍历数组。示例:
复制
1
2
3
4
5
6
7
8
9
10
11int[] nums = {1, 2, 3, 4, 5};
// 使用 for 循环
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
// 使用 for-each 循环
for (int num : nums) {
System.out.println(num);
}
字符串
将两个二进制字符串相加并以二进制字符串的形式返回结果。
从字符串的末尾(最低位)开始逐位相加。
使用一个变量
carry记录进位。将每一位的相加结果拼接到结果字符串中。
最后反转结果字符串,得到正确的顺序。
// 从末尾开始逐位相加 while (i >= 0 || j >= 0 || carry != 0) { int sum = carry; // 当前位的和 // 如果 a 还有位,加上 a 的当前位 if (i >= 0) { sum += a.charAt(i) - '0'; // 将字符转换为数字 i--; } // 如果 b 还有位,加上 b 的当前位 if (j >= 0) { sum += b.charAt(j) - '0'; // 将字符转换为数字 j--; } // 计算当前位的结果和进位 result.append(sum % 2); // 当前位的结果 carry = sum / 2; // 进位值 } // 反转结果字符串 return result.reverse().toString(); } public static void main(String[] args) { Solution solution = new Solution(); String a = "1010"; String b = "1011"; System.out.println(solution.addBinary(a, b)); // 输出: "10101" }
循环
if语句:根据条件执行或不执行某段代码。while循环:当条件为真时,重复执行某段代码。for循环:根据条件重复执行某段代码,通常用于遍历或计数。(1)明确目标
在设计条件判断之前,先明确程序的目标。
例如:
如果要遍历数组,条件判断可能是“是否到达数组末尾”。
如果要查找某个元素,条件判断可能是“当前元素是否等于目标值”。
(2)确定条件表达式
条件表达式是一个布尔表达式,结果为
true或false。常见的条件表达式包括:
比较运算:
==,!=,>,<,>=,<=逻辑运算:
&&(与),||(或),!(非)其他:
instanceof(类型检查),contains(集合包含检查)(3)考虑边界条件
确保条件判断覆盖所有可能的边界情况。
例如:
如果遍历数组,需要考虑数组为空的情况。
如果查找元素,需要考虑元素不存在的情况。
(4)优化条件判断
尽量使条件判断简洁、清晰。
避免重复的条件判断。
使用适当的逻辑运算符组合条件。
全局变量与局部变量区别
| 特性 | 全局变量 | 局部变量 |
|---|---|---|
| 作用域 | 整个类中都可以访问 | 仅限于定义它的方法、代码块或循环内部 |
| 生命周期 | 从对象创建到对象销毁 | 从变量定义开始,到方法、代码块或循环结束 |
| 默认值 | 有默认值(如 int 默认为 0) |
没有默认值,必须显式初始化 |
| 访问权限 | 可以被类中的所有方法访问 | 只能在定义它的方法、代码块或循环中访问 |
| 内存分配 | 存储在堆内存中 | 存储在栈内存中 |




