Skip to content

Commit

Permalink
增加题解
Browse files Browse the repository at this point in the history
  • Loading branch information
Damaer committed Oct 10, 2021
1 parent 961ceb9 commit ad1a0bd
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 3 deletions.
26 changes: 26 additions & 0 deletions Solution/src/com/aphysia/leetcode/Solution6.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.aphysia.leetcode;

public class Solution6 {
public static void main(String[] args) {
System.out.println(convert("PAYPALISHIRING", 4));
}

public static String convert(String s, int numRows) {
if (numRows <= 1) {
return s;
}
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < numRows; i++) {
int sum = 2 * (numRows - 1);
int gap = (numRows - i - 1) * 2;
for (int j = i; j < s.length(); ) {
if (gap != 0) {
stringBuffer.append(s.charAt(j));
}
j = j + gap;
gap = sum - gap;
}
}
return stringBuffer.toString();
}
}
7 changes: 6 additions & 1 deletion _sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,10 @@
* [53. 表示数值的字符串](/剑指Offer/剑指Offer53-表示数值的字符串.md)
* [54. 字符流中第一个不重复的字符](/剑指Offer/剑指Offer54-字符流中第一个不重复的字符.md)
* LeetCode
* [1.两数之和](/leetcode/(1)两数之和.md)
* [1.两数之和](/leetcode/leetcode1.md)
* [2.两数相加](/leetcode/leetcode2.md)
* [3.无重复字符的最长子串](/leetcode/leetcode3.md)
* [4.寻找两个正序数组的中位数](/leetcode/leetcode4.md)
* [5.最长回文子串](/leetcode/leetcode5.md)
* [6.Z字型变换](/leetcode/leetcode6.md)

3 changes: 3 additions & 0 deletions leetcode/leetcode2.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
## 题目
给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。
Expand All @@ -6,6 +7,8 @@
> 输出:7 -> 0 -> 8
> 原因:342 + 465 = 807
## 思路与解答

思路:三种情况需要循环,也就是只要有一个数字还有更高位或者有进位的时候,在这里面需要一个变量来保存进位,没有进位的时候,该变量置为0;

代码如下:
Expand Down
2 changes: 1 addition & 1 deletion leetcode/leetcode3.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ s 由英文字母、数字、符号和空格组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters

## 思路以及解答
## 思路与解答
这是一道滑动窗口的经典题目,也就是有两个指针,`low``high`,同时借助一个`hashmap`,遍历到每一个字符的时候,都要判断`hashmap`里面是否已经包含。
- 如果不包含该字符,那么直接添加进去.
- 如果已经包含该字符,则根据`key`取出`value`,也就是它的上一次出现的索引位置。
Expand Down
2 changes: 1 addition & 1 deletion leetcode/leetcode4.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ nums2.length == n
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。

## 思路以及解答
## 思路与解答
思路一:数组是有序的,利用双指针分别指向数组的第一个元素,对比大小,分别往后移动,合并到新的数组,然后直接取出中位数。
```java
class Solution {
Expand Down
174 changes: 174 additions & 0 deletions leetcode/leetcode6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
## 题目
将一个给定字符串 `s` 根据给定的行数 `numRows` ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "`PAYPALISHIRING`" 行数为 `3` 时,排列如下:
```txt
P A H N
A P L S I I G
Y I R
```
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"`PAHNAPLSIIGYIR`"。

请你实现这个将字符串进行指定行数变换的函数:`string convert(string s, int numRows);`

**示例 1:**

- 输入:s = "PAYPALISHIRING", numRows = 3
- 输出:"PAHNAPLSIIGYIR"

**示例 2:**

- 输入:s = "PAYPALISHIRING", numRows = 4
- 输出:"PINALSIGYAHRPI"

解释:
```txt
P I N
A L S I G
Y A H R
P I
```

**示例 3:**

- 输入:s = "A", numRows = 1
- 输出:"A"

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zigzag-conversion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

## 思路以及解答

原来的顺序是 "Z" 字型的,我们用小方块来模拟位置摆放:

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211009233833.png)

现在需要按照每一行来遍历:

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010012458.png)

那么我们就要先找到里面的规律,首先按照每一行遍历,那么每行有行号,遍历的时候,按照 从第 `0` 行到 第 `row-1` 行(也就是最外层循环):

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010013734.png)

那么每一行需要怎么处理呢?

需要我们发现每一行的规律,我们用 `row = 6``i = 3`的行来摸索,也就是 6 行中的第 3行:

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010014304.png)

【看 `i = 3` 的行】从第一个方块到第二个方块,其实间隔的方块数就是就是下面的红色部分,当前为 第 `i`行,下面还有 `row-1-i` 行,下面的红色方块的数量计算为:
每一行都是两个方块除了最下面一行只有一个,所以是 `行数*2-1` ,即 `(row-1-i)*2-1`,所以从第一个方块到第二个方块,中间间隔了 `方块数 = (row-1-i)*2-1` 个方块,那么只要第一个位置加上 `方块数+1`,就可以得到第二个方块的位置。

```txt
gap = 方块数 + 1 = (row - 1 - i) * 2
```

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010015127.png)

下面我们看第 `3` 行,第二个方块到第三个方块,间隔的是上面的红色方块,第 `i` 行上面还有 `i` 行,每一行都有两个方块,除了第一行,所以上面方块数为 `2*i-1`,间隔的 gap:

```txt
gap = 方块数 + 1 = 2 * i
```

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010124408.png)

我们接着看第 `3` 行,第三个方块到第四个方块,其实重复了前面的第一个方块到第二个方块的过程:

```txt
gap = 方块数 + 1 = (row - 1 - i) * 2
```

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010015839.png)

至此,我们发现了其中的规律,每一行中的间隔是不断循环的过程,每个循环的过程,又分为两个阶段:
```txt
阶段1: gap1 = 方块数 + 1 = (row - 1 - i) * 2
阶段2: gap2 = 方块数 + 1 = 2 * i
```
![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010124624.png)

每一行循环的结束条件是:**不能超过字符串长度** ,每个循环里面的两个间隔`gap` 其实用 `flag` 不断变化也是可以的, 但是我们发现它们的和是固定的 `(row - 1) * 2`

```txt
sum = gap1 + gap2 = (row - 1 - i) * 2 + 2 * i = (row - 1) * 2
```

那就好办,每次用 `sum - gap` 就可以得到下一次的 `gap`

**特殊情况:**
第一行和第二行,每一个循环中有一个 `gap``0`, `gap` 为 0 的时候我们不能重复打印该位置的字符:

![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/20211010125812.png)

Java 代码实现:

```Java
public class Solution6 {
public static void main(String[] args) {
System.out.println(convert("PAYPALISHIRING", 4));
}

public static String convert(String s, int numRows) {
if (numRows <= 1) {
return s;
}
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < numRows; i++) {
int sum = 2 * (numRows - 1);
int gap = (numRows - i - 1) * 2;
for (int j = i; j < s.length(); ) {
if (gap != 0) {
stringBuffer.append(s.charAt(j));
}
j = j + gap;
gap = sum - gap;
}
}
return stringBuffer.toString();
}
}
```

C++ 代码实现:

```c++
#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
string convert(string s, int numRows) {
if (numRows <= 1) {
return s;
}
string str;
for (int i = 0; i < numRows; i++) {
int sum = 2 * (numRows - 1);
int gap = (numRows - i - 1) * 2;
for (int j = i; j < s.length(); ) {
if (gap != 0) {
str += s[j];
}
j = j + gap;
gap = sum - gap;
}
}
return str;
}
};
int main(){
Solution solution;
string str = "PAYPALISHIRING";
cout<< solution.convert(str,4)<<endl;
return 0;
}
```
至于时间复杂度,看似是两层循环,实则不是O(n^2^), 只是遍历完了里面所有的字符,所以为O(n)。
今日总结:
> 算法题有时候就是找规律(苦笑...)

0 comments on commit ad1a0bd

Please sign in to comment.