auto commit
This commit is contained in:
parent
45d251eda3
commit
89aefa963b
|
@ -35,17 +35,21 @@ Java 的 I/O 大概可以分成以下几类:
|
|||
|
||||
# 二、磁盘操作
|
||||
|
||||
File 类可以用于表示文件和目录,但是它只用于表示文件的信息,而不表示文件的内容。
|
||||
File 类可以用于表示文件和目录的信息,但是它不表示文件的内容。
|
||||
|
||||
递归地输出一个目录下所有文件:
|
||||
|
||||
```java
|
||||
public static void listAllFiles(File dir) {
|
||||
public static void listAllFiles(File dir)
|
||||
{
|
||||
if (dir == null || !dir.exists()) {
|
||||
return;
|
||||
}
|
||||
if (dir.isFile()) {
|
||||
System.out.println(dir.getName());
|
||||
return;
|
||||
}
|
||||
for (File file : dir.listFiles()) {
|
||||
for (File file : Objects.requireNonNull(dir.listFiles())) {
|
||||
listAllFiles(file);
|
||||
}
|
||||
}
|
||||
|
@ -56,12 +60,13 @@ public static void listAllFiles(File dir) {
|
|||
使用字节流操作进行文件复制:
|
||||
|
||||
```java
|
||||
public static void copyFile(String src, String dist) throws IOException {
|
||||
FileInputStream in = new FileInputStream("file/1.txt");
|
||||
FileOutputStream out = new FileOutputStream("file/2.txt");
|
||||
public static void copyFile(String src, String dist) throws IOException
|
||||
{
|
||||
FileInputStream in = new FileInputStream(src);
|
||||
FileOutputStream out = new FileOutputStream(dist);
|
||||
byte[] buffer = new byte[20 * 1024];
|
||||
// read() 最多读取 buffer.length 个字节,返回的是实际读取的个数
|
||||
// 返回 -1 的时候表示读到 eof,即文件尾
|
||||
/* read() 最多读取 buffer.length 个字节
|
||||
返回的是实际读取的个数,返回 -1 的时候表示读到 eof,即文件尾 */
|
||||
while (in.read(buffer, 0, buffer.length) != -1) {
|
||||
out.write(buffer);
|
||||
}
|
||||
|
@ -87,7 +92,8 @@ DataInputStream 装饰者提供了对更多数据类型进行输入的操作,
|
|||
|
||||
不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符。但是在程序中操作的通常是字符形式的数据,因此需要提供对字符进行操作的方法。
|
||||
|
||||
InputStreamReader 实现从文本文件的字节流解码成字符流;OutputStreamWriter 实现字符流编码成为文本文件的字节流。
|
||||
- InputStreamReader 实现从文本文件的字节流解码成字符流;
|
||||
- OutputStreamWriter 实现字符流编码成为文本文件的字节流。
|
||||
|
||||
逐行输出文本文件的内容:
|
||||
|
||||
|
@ -98,8 +104,9 @@ String line;
|
|||
while ((line = bufferedReader.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
}
|
||||
// 装饰者模式使得 BufferedReader 组合了一个 Reader 对象
|
||||
// 在调用 BufferedReader 的 close() 方法时会去调用 fileReader 的 close() 方法,因此只要一个 close() 调用即可
|
||||
/* 装饰者模式使得 BufferedReader 组合了一个 Reader 对象
|
||||
在调用 BufferedReader 的 close() 方法时会去调用 fileReader 的 close() 方法
|
||||
因此只要一个 close() 调用即可 */
|
||||
bufferedReader.close();
|
||||
```
|
||||
|
||||
|
@ -140,31 +147,35 @@ byte[] bytes = str1.getBytes();
|
|||
序列化的类需要实现 Serializable 接口,它只是一个标准,没有任何方法需要实现,但是如果不去实现它的话而进行序列化,会抛出异常。
|
||||
|
||||
```java
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException {
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException
|
||||
{
|
||||
A a1 = new A(123, "abc");
|
||||
String objectFile = "file/a1";
|
||||
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(objectFile));
|
||||
objectOutputStream.writeObject(a1);
|
||||
objectOutputStream.close();
|
||||
|
||||
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(objectFile));
|
||||
A a2 = (A) objectInputStream.readObject();
|
||||
objectInputStream.close();
|
||||
System.out.println(a2);
|
||||
}
|
||||
|
||||
private static class A implements Serializable {
|
||||
private static class A implements Serializable
|
||||
{
|
||||
private int x;
|
||||
private String y;
|
||||
|
||||
A(int x, String y) {
|
||||
A(int x, String y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "x = " + x +
|
||||
" " + "y = " + y;
|
||||
public String toString()
|
||||
{
|
||||
return "x = " + x + " " + "y = " + y;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -202,16 +213,19 @@ InetAddress.getByAddress(byte[] address);
|
|||
可以直接从 URL 中读取字节流数据。
|
||||
|
||||
```java
|
||||
URL url = new URL("http://www.baidu.com");
|
||||
InputStream is = url.openStream(); // 字节流
|
||||
InputStreamReader isr = new InputStreamReader(is, "utf-8"); // 字符流
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line = br.readLine();
|
||||
while (line != null) {
|
||||
System.out.println(line);
|
||||
line = br.readLine();
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
URL url = new URL("http://www.baidu.com");
|
||||
InputStream is = url.openStream(); /* 字节流 */
|
||||
InputStreamReader isr = new InputStreamReader(is, "utf-8"); /* 字符流 */
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line = br.readLine();
|
||||
while (line != null) {
|
||||
System.out.println(line);
|
||||
line = br.readLine();
|
||||
}
|
||||
br.close();
|
||||
}
|
||||
br.close();
|
||||
```
|
||||
|
||||
## Sockets
|
||||
|
|
|
@ -2526,7 +2526,8 @@ public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
|
|||
正确的解法应该是和书上一样,先旋转每个单词,再旋转整个字符串。
|
||||
|
||||
```java
|
||||
public String ReverseSentence(String str) {
|
||||
public String ReverseSentence(String str)
|
||||
{
|
||||
int n = str.length();
|
||||
char[] chars = str.toCharArray();
|
||||
int i = 0, j = 0;
|
||||
|
@ -2541,12 +2542,14 @@ public String ReverseSentence(String str) {
|
|||
return new String(chars);
|
||||
}
|
||||
|
||||
private void reverse(char[] c, int i, int j) {
|
||||
private void reverse(char[] c, int i, int j)
|
||||
{
|
||||
while (i < j)
|
||||
swap(c, i++, j--);
|
||||
}
|
||||
|
||||
private void swap(char[] c, int i, int j) {
|
||||
private void swap(char[] c, int i, int j)
|
||||
{
|
||||
char t = c[i];
|
||||
c[i] = c[j];
|
||||
c[j] = t;
|
||||
|
@ -2566,7 +2569,8 @@ private void swap(char[] c, int i, int j) {
|
|||
将 "abcXYZdef" 旋转左移三位,可以先将 "abc" 和 "XYZdef" 分别旋转,得到 "cbafedZYX",然后再把整个字符串旋转得到 "XYZdefabc"。
|
||||
|
||||
```java
|
||||
public String LeftRotateString(String str, int n) {
|
||||
public String LeftRotateString(String str, int n)
|
||||
{
|
||||
if (n >= str.length())
|
||||
return str;
|
||||
char[] chars = str.toCharArray();
|
||||
|
@ -2576,12 +2580,14 @@ public String LeftRotateString(String str, int n) {
|
|||
return new String(chars);
|
||||
}
|
||||
|
||||
private void reverse(char[] chars, int i, int j) {
|
||||
private void reverse(char[] chars, int i, int j)
|
||||
{
|
||||
while (i < j)
|
||||
swap(chars, i++, j--);
|
||||
}
|
||||
|
||||
private void swap(char[] chars, int i, int j) {
|
||||
private void swap(char[] chars, int i, int j)
|
||||
{
|
||||
char t = chars[i];
|
||||
chars[i] = chars[j];
|
||||
chars[j] = t;
|
||||
|
@ -2599,15 +2605,16 @@ private void swap(char[] chars, int i, int j) {
|
|||
## 解题思路
|
||||
|
||||
```java
|
||||
public ArrayList<Integer> maxInWindows(int[] num, int size) {
|
||||
public ArrayList<Integer> maxInWindows(int[] num, int size)
|
||||
{
|
||||
ArrayList<Integer> ret = new ArrayList<>();
|
||||
PriorityQueue<Integer> heap = new PriorityQueue<Integer>((o1, o2) -> o2 - o1);
|
||||
if (size > num.length || size < 1)
|
||||
return ret;
|
||||
PriorityQueue<Integer> heap = new PriorityQueue<>((o1, o2) -> o2 - o1); /* 大顶堆 */
|
||||
for (int i = 0; i < size; i++)
|
||||
heap.add(num[i]);
|
||||
ret.add(heap.peek());
|
||||
for (int i = 1, j = i + size - 1; j < num.length; i++, j++) {
|
||||
for (int i = 1, j = i + size - 1; j < num.length; i++, j++) { /* 维护一个大小为 size 的大顶堆 */
|
||||
heap.remove(num[i - 1]);
|
||||
heap.add(num[j]);
|
||||
ret.add(heap.peek());
|
||||
|
@ -2633,15 +2640,17 @@ public ArrayList<Integer> maxInWindows(int[] num, int size) {
|
|||
空间复杂度:O(N<sup>2</sup>)
|
||||
|
||||
```java
|
||||
public List<Map.Entry<Integer, Double>> dicesSum(int n) {
|
||||
public List<Map.Entry<Integer, Double>> dicesSum(int n)
|
||||
{
|
||||
final int face = 6;
|
||||
final int pointNum = face * n;
|
||||
long[][] dp = new long[n + 1][pointNum + 1];
|
||||
|
||||
for (int i = 1; i <= face; i++)
|
||||
dp[1][i] = 1;
|
||||
|
||||
for (int i = 2; i <= n; i++)
|
||||
for (int j = i; j <= pointNum; j++) // 使用 i 个骰子最小点数为 i
|
||||
for (int j = i; j <= pointNum; j++) /* 使用 i 个骰子最小点数为 i */
|
||||
for (int k = 1; k <= face && k <= j; k++)
|
||||
dp[i][j] += dp[i - 1][j - k];
|
||||
|
||||
|
@ -2649,6 +2658,7 @@ public List<Map.Entry<Integer, Double>> dicesSum(int n) {
|
|||
List<Map.Entry<Integer, Double>> ret = new ArrayList<>();
|
||||
for (int i = n; i <= pointNum; i++)
|
||||
ret.add(new AbstractMap.SimpleEntry<>(i, dp[n][i] / totalNum));
|
||||
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
@ -2658,24 +2668,30 @@ public List<Map.Entry<Integer, Double>> dicesSum(int n) {
|
|||
空间复杂度:O(N)
|
||||
|
||||
```java
|
||||
public List<Map.Entry<Integer, Double>> dicesSum(int n) {
|
||||
public List<Map.Entry<Integer, Double>> dicesSum(int n)
|
||||
{
|
||||
final int face = 6;
|
||||
final int pointNum = face * n;
|
||||
long[][] dp = new long[2][pointNum + 1];
|
||||
|
||||
for (int i = 1; i <= face; i++)
|
||||
dp[0][i] = 1;
|
||||
int flag = 1;
|
||||
|
||||
int flag = 1; /* 旋转标记 */
|
||||
for (int i = 2; i <= n; i++, flag = 1 - flag) {
|
||||
for (int j = 0; j <= pointNum; j++)
|
||||
dp[flag][j] = 0; // 旋转数组清零
|
||||
for (int j = i; j <= pointNum; j++) // 使用 i 个骰子最小点数为 i
|
||||
dp[flag][j] = 0; /* 旋转数组清零 */
|
||||
|
||||
for (int j = i; j <= pointNum; j++)
|
||||
for (int k = 1; k <= face && k <= j; k++)
|
||||
dp[flag][j] += dp[1 - flag][j - k];
|
||||
}
|
||||
|
||||
final double totalNum = Math.pow(6, n);
|
||||
List<Map.Entry<Integer, Double>> ret = new ArrayList<>();
|
||||
for (int i = n; i <= pointNum; i++)
|
||||
ret.add(new AbstractMap.SimpleEntry<>(i, dp[1 - flag][i] / totalNum));
|
||||
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
@ -2691,18 +2707,20 @@ public List<Map.Entry<Integer, Double>> dicesSum(int n) {
|
|||
## 解题思路
|
||||
|
||||
```java
|
||||
public boolean isContinuous(int[] nums) {
|
||||
public boolean isContinuous(int[] nums)
|
||||
{
|
||||
if (nums.length < 5)
|
||||
return false;
|
||||
Arrays.sort(nums);
|
||||
int cnt = 0;
|
||||
for (int num : nums)
|
||||
for (int num : nums) /* 统计癞子数量 */
|
||||
if (num == 0)
|
||||
cnt++;
|
||||
|
||||
for (int i = cnt; i < nums.length - 1; i++) {
|
||||
if (nums[i + 1] == nums[i])
|
||||
return false;
|
||||
cnt -= nums[i + 1] - nums[i] - 1;
|
||||
cnt -= nums[i + 1] - nums[i] - 1; /* 使用癞子去补全不连续的顺子 */
|
||||
}
|
||||
return cnt >= 0;
|
||||
}
|
||||
|
@ -2721,10 +2739,11 @@ public boolean isContinuous(int[] nums) {
|
|||
约瑟夫环,圆圈长度为 n 的解可以看成长度为 n-1 的解再加上报数的长度 m。因为是圆圈,所以最后需要对 n 取余。
|
||||
|
||||
```java
|
||||
public int LastRemaining_Solution(int n, int m) {
|
||||
if (n == 0)
|
||||
public int LastRemaining_Solution(int n, int m)
|
||||
{
|
||||
if (n == 0) /* 特殊输入的处理 */
|
||||
return -1;
|
||||
if (n == 1)
|
||||
if (n == 1) /* 返回条件 */
|
||||
return 0;
|
||||
return (LastRemaining_Solution(n - 1, m) + m) % n;
|
||||
}
|
||||
|
@ -2743,13 +2762,13 @@ public int LastRemaining_Solution(int n, int m) {
|
|||
使用贪心策略,假设第 i 轮进行卖出操作,买入操作价格应该在 i 之前并且价格最低。
|
||||
|
||||
```java
|
||||
public int maxProfit(int[] prices) {
|
||||
public int maxProfit(int[] prices)
|
||||
{
|
||||
if (prices == null || prices.length == 0)
|
||||
return 0;
|
||||
int n = prices.length;
|
||||
int soFarMin = prices[0];
|
||||
int maxProfit = 0;
|
||||
for (int i = 1; i < n; i++) {
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
soFarMin = Math.min(soFarMin, prices[i]);
|
||||
maxProfit = Math.max(maxProfit, prices[i] - soFarMin);
|
||||
}
|
||||
|
@ -2774,7 +2793,8 @@ public int maxProfit(int[] prices) {
|
|||
以下实现中,递归的返回条件为 n <= 0,取非后就是 n > 0,递归的主体部分为 sum += Sum_Solution(n - 1),转换为条件语句后就是 (sum += Sum_Solution(n - 1)) > 0。
|
||||
|
||||
```java
|
||||
public int Sum_Solution(int n) {
|
||||
public int Sum_Solution(int n)
|
||||
{
|
||||
int sum = n;
|
||||
boolean b = (n > 0) && ((sum += Sum_Solution(n - 1)) > 0);
|
||||
return sum;
|
||||
|
@ -2796,8 +2816,9 @@ a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进
|
|||
递归会终止的原因是 (a & b) << 1 最右边会多一个 0,那么继续递归,进位最右边的 0 会慢慢增多,最后进位会变为 0,递归终止。
|
||||
|
||||
```java
|
||||
public int Add(int num1, int num2) {
|
||||
return num2 == 0 ? num1 : Add(num1 ^ num2, (num1 & num2) << 1);
|
||||
public int Add(int a, int b)
|
||||
{
|
||||
return b == 0 ? a : Add(a ^ b, (a & b) << 1);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2812,12 +2833,13 @@ public int Add(int num1, int num2) {
|
|||
## 解题思路
|
||||
|
||||
```java
|
||||
public int[] multiply(int[] A) {
|
||||
public int[] multiply(int[] A)
|
||||
{
|
||||
int n = A.length;
|
||||
int[] B = new int[n];
|
||||
for (int i = 0, product = 1; i < n; product *= A[i], i++)
|
||||
for (int i = 0, product = 1; i < n; product *= A[i], i++) /* 从左往右累乘 */
|
||||
B[i] = product;
|
||||
for (int i = n - 1, product = 1; i >= 0; product *= A[i], i--)
|
||||
for (int i = n - 1, product = 1; i >= 0; product *= A[i], i--) /* 从右往左累乘 */
|
||||
B[i] *= product;
|
||||
return B;
|
||||
}
|
||||
|
@ -2844,17 +2866,18 @@ Output:
|
|||
## 解题思路
|
||||
|
||||
```java
|
||||
public int StrToInt(String str) {
|
||||
public int StrToInt(String str)
|
||||
{
|
||||
if (str == null || str.length() == 0)
|
||||
return 0;
|
||||
boolean isNegative = str.charAt(0) == '-';
|
||||
int ret = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
if (i == 0 && (c == '+' || c == '-'))
|
||||
if (i == 0 && (c == '+' || c == '-')) /* 符号判定 */
|
||||
continue;
|
||||
if (c < '0' || c > '9')
|
||||
return 0; // 非法输入
|
||||
if (c < '0' || c > '9') /* 非法输入 */
|
||||
return 0;
|
||||
ret = ret * 10 + (c - '0');
|
||||
}
|
||||
return isNegative ? -ret : ret;
|
||||
|
@ -2891,7 +2914,7 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
|||
|
||||
[Leetcode : 236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/)
|
||||
|
||||
在左右子树中查找两个节点的最低公共祖先,如果在其中一颗子树中查找到,那么就返回这个解,否则可以认为根节点就是最低公共祖先。
|
||||
在左右子树中查找是否存在 p 或者 q,如果 p 和 q 分别在两个子树中,那么就说明根节点就是 LCA。
|
||||
|
||||
```java
|
||||
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user