Skip to content

Commit c3fe66c

Browse files
committed
feat: add solutions to lc problem: No.1163
No.1163.Last Substring in Lexicographical Order
1 parent 59ddbbd commit c3fe66c

File tree

7 files changed

+352
-2
lines changed

7 files changed

+352
-2
lines changed

solution/1100-1199/1163.Last Substring in Lexicographical Order/README.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,149 @@
3838

3939
<!-- 这里可写通用的实现逻辑 -->
4040

41+
**方法一:双指针**
42+
43+
我们注意到,如果一个子串从位置 $i$ 开始,那么字典序最大的子串一定是 $s[i,..n-1]$,即从位置 $i$ 开始的最长后缀。因此,我们只需要找出字典序最大的后缀子串即可。
44+
45+
我们使用双指针 $i$ 和 $j$,其中指针 $i$ 指向当前字典序最大的子串的起始位置,指针 $j$ 指向当前考虑的子串的起始位置。另外,用一个变量 $k$ 记录当前比较到的位置。初始时 $i = 0$, $j=1$, $k=0$。
46+
47+
每一次,我们比较 $s[i+k]$ 和 $s[j+k]$:
48+
49+
如果 $s[i + k] = s[j + k]$,说明 $s[i,..i+k]$ 和 $s[j,..j+k]$ 相同,我们将 $k$ 加 $1$,继续比较 $s[i+k]$ 和 $s[j+k]$;
50+
51+
如果 $s[i + k] \lt s[j + k]$,说明 $s[j,..j+k]$ 的字典序更大。此时,我们更新 $i = i + k + 1$,并将 $k$ 重置为 $0$。如果此时 $i \geq j$,那么我们将指针 $j$ 更新为 $i + 1$,即 $j = i + 1$。这里我们跳过了以 $s[i,..,i+k]$ 为起始位置的所有后缀子串,因为它们的字典序一定小于对应的 $s[j,..,j+k]$ 为起始位置的后缀子串。
52+
53+
同理,如果 $s[i + k] \gt s[j + k]$,说明 $s[i,..,i+k]$ 的字典序更大。此时,我们更新 $j = j + k + 1$,并将 $k$ 重置为 $0$。这里我们跳过了以 $s[j,..,j+k]$ 为起始位置的所有后缀子串,因为它们的字典序一定小于对应的 $s[i,..,i+k]$ 为起始位置的后缀子串。
54+
55+
最后,我们返回以 $i$ 为起始位置的后缀子串即可,即 $s[i,..,n-1]$。
56+
57+
时间复杂度 $O(n)$,其中 $n$ 为字符串 $s$ 的长度。空间复杂度 $O(1)$。
58+
4159
<!-- tabs:start -->
4260

4361
### **Python3**
4462

4563
<!-- 这里可写当前语言的特殊实现逻辑 -->
4664

4765
```python
48-
66+
class Solution:
67+
def lastSubstring(self, s: str) -> str:
68+
i, j, k = 0, 1, 0
69+
while j + k < len(s):
70+
if s[i + k] == s[j + k]:
71+
k += 1
72+
elif s[i + k] < s[j + k]:
73+
i += k + 1
74+
k = 0
75+
if i >= j:
76+
j = i + 1
77+
else:
78+
j += k + 1
79+
k = 0
80+
return s[i:]
4981
```
5082

5183
### **Java**
5284

5385
<!-- 这里可写当前语言的特殊实现逻辑 -->
5486

5587
```java
88+
class Solution {
89+
public String lastSubstring(String s) {
90+
int n = s.length();
91+
int i = 0;
92+
for (int j = 1, k = 0; j + k < n;) {
93+
int d = s.charAt(i + k) - s.charAt(j + k);
94+
if (d == 0) {
95+
++k;
96+
} else if (d < 0) {
97+
i += k + 1;
98+
k = 0;
99+
if (i >= j) {
100+
j = i + 1;
101+
}
102+
} else {
103+
j += k + 1;
104+
k = 0;
105+
}
106+
}
107+
return s.substring(i);
108+
}
109+
}
110+
```
111+
112+
### **C++**
113+
114+
```cpp
115+
class Solution {
116+
public:
117+
string lastSubstring(string s) {
118+
int n = s.size();
119+
int i = 0;
120+
for (int j = 1, k = 0; j + k < n;) {
121+
if (s[i + k] == s[j + k]) {
122+
++k;
123+
} else if (s[i + k] < s[j + k]) {
124+
i += k + 1;
125+
k = 0;
126+
if (i >= j) {
127+
j = i + 1;
128+
}
129+
} else {
130+
j += k + 1;
131+
k = 0;
132+
}
133+
}
134+
return s.substr(i);
135+
}
136+
};
137+
```
138+
139+
### **Go**
140+
141+
```go
142+
func lastSubstring(s string) string {
143+
i, n := 0, len(s)
144+
for j, k := 1, 0; j+k < n; {
145+
if s[i+k] == s[j+k] {
146+
k++
147+
} else if s[i+k] < s[j+k] {
148+
i += k + 1
149+
k = 0
150+
if i >= j {
151+
j = i + 1
152+
}
153+
} else {
154+
j += k + 1
155+
k = 0
156+
}
157+
}
158+
return s[i:]
159+
}
160+
```
56161

162+
### **TypeScript**
163+
164+
```ts
165+
function lastSubstring(s: string): string {
166+
const n = s.length;
167+
let i = 0;
168+
for (let j = 1, k = 0; j + k < n; ) {
169+
if (s[i + k] === s[j + k]) {
170+
++k;
171+
} else if (s[i + k] < s[j + k]) {
172+
i += k + 1;
173+
k = 0;
174+
if (i >= j) {
175+
j = i + 1;
176+
}
177+
} else {
178+
j += k + 1;
179+
k = 0;
180+
}
181+
}
182+
return s.slice(i);
183+
}
57184
```
58185

59186
### **...**

solution/1100-1199/1163.Last Substring in Lexicographical Order/README_EN.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,145 @@
3232

3333
## Solutions
3434

35+
**Approach 1: Two pointers**
36+
37+
We notice that if a substring starts from position $i$, then the largest substring with the largest dictionary order must be $s[i,..n-1]$, which is the longest suffix starting from position $i$. Therefore, we only need to find the largest suffix substring.
38+
39+
We use two pointers $i$ and $j$, where pointer $i$ points to the starting position of the current largest substring with the largest dictionary order, and pointer $j$ points to the starting position of the current substring being considered. In addition, we use a variable $k$ to record the current position being compared. Initially, $i = 0$, $j=1$, $k=0$.
40+
41+
Each time, we compare $s[i+k]$ and $s[j+k]$:
42+
43+
If $s[i + k] = s[j + k]$, it means that $s[i,..i+k]$ and $s[j,..j+k]$ are the same, and we add $k$ by $1$ and continue to compare $s[i+k]$ and $s[j+k]$;
44+
45+
If $s[i + k] \lt s[j + k]$, it means that the dictionary order of $s[j,..j+k]$ is larger. At this time, we update $i = i + k + 1$, and reset $k$ to $0$. If $i \geq j$ at this time, we update pointer $j$ to $i + 1$, that is, $j = i + 1$. Here we skip all suffix substrings with $s[i,..,i+k]$ as the starting position, because their dictionary orders are smaller than the suffix substrings with $s[j,..,j+k]$ as the starting position.
46+
47+
Similarly, if $s[i + k] \gt s[j + k]$, it means that the dictionary order of $s[i,..,i+k]$ is larger. At this time, we update $j = j + k + 1$ and reset $k$ to $0$. Here we skip all suffix substrings with $s[j,..,j+k]$ as the starting position, because their dictionary orders are smaller than the suffix substrings with $s[i,..,i+k]$ as the starting position.
48+
49+
Finally, we return the suffix substring starting from $i$, that is, $s[i,..,n-1]$.
50+
51+
The time complexity is $O(n)$, where $n$ is the length of string $s$. The space complexity is $O(1)$.
52+
3553
<!-- tabs:start -->
3654

3755
### **Python3**
3856

3957
```python
40-
58+
class Solution:
59+
def lastSubstring(self, s: str) -> str:
60+
i, j, k = 0, 1, 0
61+
while j + k < len(s):
62+
if s[i + k] == s[j + k]:
63+
k += 1
64+
elif s[i + k] < s[j + k]:
65+
i += k + 1
66+
k = 0
67+
if i >= j:
68+
j = i + 1
69+
else:
70+
j += k + 1
71+
k = 0
72+
return s[i:]
4173
```
4274

4375
### **Java**
4476

4577
```java
78+
class Solution {
79+
public String lastSubstring(String s) {
80+
int n = s.length();
81+
int i = 0;
82+
for (int j = 1, k = 0; j + k < n;) {
83+
int d = s.charAt(i + k) - s.charAt(j + k);
84+
if (d == 0) {
85+
++k;
86+
} else if (d < 0) {
87+
i += k + 1;
88+
k = 0;
89+
if (i >= j) {
90+
j = i + 1;
91+
}
92+
} else {
93+
j += k + 1;
94+
k = 0;
95+
}
96+
}
97+
return s.substring(i);
98+
}
99+
}
100+
```
101+
102+
### **C++**
103+
104+
```cpp
105+
class Solution {
106+
public:
107+
string lastSubstring(string s) {
108+
int n = s.size();
109+
int i = 0;
110+
for (int j = 1, k = 0; j + k < n;) {
111+
if (s[i + k] == s[j + k]) {
112+
++k;
113+
} else if (s[i + k] < s[j + k]) {
114+
i += k + 1;
115+
k = 0;
116+
if (i >= j) {
117+
j = i + 1;
118+
}
119+
} else {
120+
j += k + 1;
121+
k = 0;
122+
}
123+
}
124+
return s.substr(i);
125+
}
126+
};
127+
```
128+
129+
### **Go**
130+
131+
```go
132+
func lastSubstring(s string) string {
133+
i, n := 0, len(s)
134+
for j, k := 1, 0; j+k < n; {
135+
if s[i+k] == s[j+k] {
136+
k++
137+
} else if s[i+k] < s[j+k] {
138+
i += k + 1
139+
k = 0
140+
if i >= j {
141+
j = i + 1
142+
}
143+
} else {
144+
j += k + 1
145+
k = 0
146+
}
147+
}
148+
return s[i:]
149+
}
150+
```
46151

152+
### **TypeScript**
153+
154+
```ts
155+
function lastSubstring(s: string): string {
156+
const n = s.length;
157+
let i = 0;
158+
for (let j = 1, k = 0; j + k < n; ) {
159+
if (s[i + k] === s[j + k]) {
160+
++k;
161+
} else if (s[i + k] < s[j + k]) {
162+
i += k + 1;
163+
k = 0;
164+
if (i >= j) {
165+
j = i + 1;
166+
}
167+
} else {
168+
j += k + 1;
169+
k = 0;
170+
}
171+
}
172+
return s.slice(i);
173+
}
47174
```
48175

49176
### **...**
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
class Solution {
2+
public:
3+
string lastSubstring(string s) {
4+
int n = s.size();
5+
int i = 0;
6+
for (int j = 1, k = 0; j + k < n;) {
7+
if (s[i + k] == s[j + k]) {
8+
++k;
9+
} else if (s[i + k] < s[j + k]) {
10+
i += k + 1;
11+
k = 0;
12+
if (i >= j) {
13+
j = i + 1;
14+
}
15+
} else {
16+
j += k + 1;
17+
k = 0;
18+
}
19+
}
20+
return s.substr(i);
21+
}
22+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
func lastSubstring(s string) string {
2+
i, n := 0, len(s)
3+
for j, k := 1, 0; j+k < n; {
4+
if s[i+k] == s[j+k] {
5+
k++
6+
} else if s[i+k] < s[j+k] {
7+
i += k + 1
8+
k = 0
9+
if i >= j {
10+
j = i + 1
11+
}
12+
} else {
13+
j += k + 1
14+
k = 0
15+
}
16+
}
17+
return s[i:]
18+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
class Solution {
2+
public String lastSubstring(String s) {
3+
int n = s.length();
4+
int i = 0;
5+
for (int j = 1, k = 0; j + k < n;) {
6+
int d = s.charAt(i + k) - s.charAt(j + k);
7+
if (d == 0) {
8+
++k;
9+
} else if (d < 0) {
10+
i += k + 1;
11+
k = 0;
12+
if (i >= j) {
13+
j = i + 1;
14+
}
15+
} else {
16+
j += k + 1;
17+
k = 0;
18+
}
19+
}
20+
return s.substring(i);
21+
}
22+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class Solution:
2+
def lastSubstring(self, s: str) -> str:
3+
i, j, k = 0, 1, 0
4+
while j + k < len(s):
5+
if s[i + k] == s[j + k]:
6+
k += 1
7+
elif s[i + k] < s[j + k]:
8+
i += k + 1
9+
k = 0
10+
if i >= j:
11+
j = i + 1
12+
else:
13+
j += k + 1
14+
k = 0
15+
return s[i:]

0 commit comments

Comments
 (0)