一、问题描述
题目描述
给定一个仅包含大小写字母和数字的字符串,要求找出其中最长的非严格递增连续数字序列的长度。非严格递增连续数字序列指的是序列中的数字从左到右依次递增或保持不变,例如 12234
就是一个非严格递增连续数字序列。
输入描述
输入一个字符串,仅包含大小写字母和数字,且字符串的最大长度不超过255个字符。
输出描述
输出字符串中最长的非严格递增连续数字序列的长度。
用例
输入: abc2234019A334bc
输出: 4
说明: 2234
是最长的非严格递增连续数字序列,因此长度为4。
双指针解法
双指针逻辑
-
初始化指针:
- 使用两个指针
left
和right
,初始时都指向字符串的起始位置。
- 使用两个指针
-
遍历字符串:
- 移动
right
指针,逐个检查字符。
- 移动
-
遇到字母时:
- 如果
right
指针指向的字符是字母,则说明前面的子串可能是一个符合题意的数字序列。 - 计算当前子串的长度
right - left
,并更新最大长度。 - 将
left
和right
指针同时移动到字母后的下一个位置,继续遍历。
- 如果
-
遇到数字时:
- 如果
left
和right
指针指向同一个位置,说明当前子串长度为1,直接记录。 - 如果
left
和right
指针不在同一个位置,则检查right
指针指向的数字是否大于或等于right-1
指针指向的数字:- 如果是,则当前子串长度增加,继续移动
right
指针。 - 如果不是,则记录当前子串长度,并将
left
和right
指针同时移动到当前位置的下一个位置,继续遍历。
- 如果是,则当前子串长度增加,继续移动
- 如果
-
结束遍历:
- 遍历结束后,再次检查最后一个子串的长度,确保没有遗漏。
总结
通过双指针的方法,可以有效地遍历字符串,并在遇到字母或不符合条件的数字时,及时更新最长非严格递增连续数字序列的长度。这种方法的时间复杂度为 O(n),其中 n 是字符串的长度。
二、JavaScript算法源码
以下是 JavaScript 代码的详细注释和讲解,帮助理解每一部分的作用和逻辑:
代码讲解
/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");
// 创建 readline 接口,用于从控制台读取输入
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 监听 'line' 事件,当用户输入一行内容时触发
rl.on("line", (line) => {
// 调用 getMaxLen 函数,计算最长非严格递增连续数字序列的长度,并输出结果
console.log(getMaxLen(line));
});
// 定义 getMaxLen 函数,用于计算最长非严格递增连续数字序列的长度
function getMaxLen(str) {
// 初始化双指针 L 和 R,分别表示当前数字序列的起始位置和结束位置
let L = 0;
let R = 0;
// 初始化 maxLen,用于记录当前找到的最长非严格递增连续数字序列的长度
let maxLen = 0;
// 遍历字符串
while (R < str.length) {
// 判断当前字符是否是数字
if (/\d/.test(str[R])) {
// 如果 L 和 R 不在同一个位置,说明当前正在处理一个数字序列
if (L !== R) {
// 判断当前字符是否大于等于前一个字符(非严格递增)
if (str[R] - 0 >= str[R - 1] - 0) {
// 如果是非严格递增,则更新当前序列的长度(R - L + 1),并更新 maxLen
maxLen = Math.max(maxLen, R - L + 1);
// 移动 R 指针,继续检查下一个字符
R++;
} else {
// 如果不是非严格递增,则记录当前序列的长度(R - L),并更新 maxLen
maxLen = Math.max(maxLen, R - L);
// 将 L 移动到 R 的位置,开始一个新的数字序列
L = R;
// 移动 R 指针,继续检查下一个字符
R++;
}
} else {
// 如果 L 和 R 在同一个位置,说明当前是一个新的数字序列,长度为 1
maxLen = Math.max(maxLen, 1);
// 移动 R 指针,继续检查下一个字符
R++;
}
} else {
// 如果当前字符不是数字,则记录当前数字序列的长度(R - L),并更新 maxLen
maxLen = Math.max(maxLen, R - L);
// 移动 R 指针到下一个字符
R++;
// 将 L 移动到 R 的位置,开始一个新的序列
L = R;
}
}
// 返回最终找到的最长非严格递增连续数字序列的长度
return maxLen;
}
代码逻辑详解
-
输入处理:
- 使用
readline
模块从控制台读取输入的字符串。 - 监听
line
事件,当用户输入一行内容时,调用getMaxLen
函数计算最长非严格递增连续数字序列的长度,并输出结果。
- 使用
-
双指针初始化:
L
和R
分别表示当前数字序列的起始位置和结束位置,初始值均为 0。maxLen
用于记录当前找到的最长非严格递增连续数字序列的长度,初始值为 0。
-
遍历字符串:
- 使用
while
循环遍历字符串,R
指针从 0 开始逐步向右移动。 - 对于每个字符
str[R]
,使用正则表达式/\d/.test(str[R])
判断其是否是数字:- 如果是数字,则进一步判断是否满足非严格递增的条件。
- 如果不是数字,则记录当前数字序列的长度,并重置
L
和R
的位置。
- 使用
-
处理数字字符:
- 如果
L
和R
不在同一个位置,说明当前正在处理一个数字序列:- 判断当前字符是否大于等于前一个字符(非严格递增)。
- 如果是非严格递增,则更新当前序列的长度(
R - L + 1
),并更新maxLen
。 - 如果不是非严格递增,则记录当前序列的长度(
R - L
),并更新maxLen
,同时将L
移动到R
的位置,开始一个新的数字序列。
- 如果
L
和R
在同一个位置,说明当前是一个新的数字序列,长度为 1,直接更新maxLen
。
- 如果
-
处理非数字字符:
- 如果当前字符不是数字,则记录当前数字序列的长度(
R - L
),并更新maxLen
。 - 将
L
和R
移动到下一个字符的位置,开始一个新的序列。
- 如果当前字符不是数字,则记录当前数字序列的长度(
-
返回结果:
- 遍历结束后,返回
maxLen
,即最长非严格递增连续数字序列的长度。
- 遍历结束后,返回
示例运行
以输入 abc2234019A334bc
为例:
- 遍历到
2
时,开始一个新的数字序列,长度为 1。 - 遍历到
2
时,满足非严格递增,序列长度变为 2。 - 遍历到
3
时,满足非严格递增,序列长度变为 3。 - 遍历到
4
时,满足非严格递增,序列长度变为 4。 - 遍历到
0
时,不满足非严格递增,记录当前序列长度 4,并开始新的序列。 - 遍历到
1
时,开始新的序列,长度为 1。 - 遍历到
9
时,满足非严格递增,序列长度变为 2。 - 遍历到
A
时,记录当前序列长度 2,并开始新的序列。 - 遍历到
3
时,开始新的序列,长度为 1。 - 遍历到
3
时,满足非严格递增,序列长度变为 2。 - 遍历到
4
时,满足非严格递增,序列长度变为 3。 - 遍历到
b
时,记录当前序列长度 3,并开始新的序列。 - 遍历到
c
时,记录当前序列长度 0。
最终,最长非严格递增连续数字序列的长度为 4(2234
)。
总结
这段 JavaScript 代码通过双指针的方法,高效地遍历字符串,动态维护当前数字序列的起始和结束位置,并在遇到字母或不满足条件的数字时,及时更新最长序列的长度。代码逻辑清晰,能够正确处理各种边界情况。
三、Java算法源码
以下是代码的详细注释和讲解,帮助理解每一部分的作用和逻辑:
代码讲解
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 创建 Scanner 对象,用于从控制台读取输入
Scanner sc = new Scanner(System.in);
// 读取输入的字符串
String s = sc.nextLine();
// 调用 getResult 方法,计算最长非严格递增连续数字序列的长度,并输出结果
System.out.println(getResult(s));
}
public static int getResult(String s) {
// 初始化双指针 l 和 r,分别表示当前数字序列的起始位置和结束位置
int l = 0;
int r = 0;
// 初始化 maxLen,用于记录当前找到的最长非严格递增连续数字序列的长度
int maxLen = 0;
// 遍历字符串
while (r < s.length()) {
// 获取当前字符
char c = s.charAt(r);
// 判断当前字符是否是数字
if (c >= '0' && c <= '9') {
// 如果 l 和 r 不在同一个位置,说明当前正在处理一个数字序列
if (l != r) {
// 判断当前字符是否大于等于前一个字符(非严格递增)
if (c >= s.charAt(r - 1)) {
// 如果是非严格递增,则更新当前序列的长度(r - l + 1),并更新 maxLen
maxLen = Math.max(maxLen, r - l + 1);
} else {
// 如果不是非严格递增,则记录当前序列的长度(r - l),并更新 maxLen
maxLen = Math.max(maxLen, r - l);
// 将 l 移动到 r 的位置,开始一个新的数字序列
l = r;
}
// 移动 r 指针,继续检查下一个字符
r++;
} else {
// 如果 l 和 r 在同一个位置,说明当前是一个新的数字序列,长度为 1
maxLen = Math.max(maxLen, 1);
// 移动 r 指针,继续检查下一个字符
r++;
}
} else {
// 如果当前字符不是数字,则记录当前数字序列的长度(r - l),并更新 maxLen
maxLen = Math.max(maxLen, r - l);
// 移动 r 指针到下一个字符
r++;
// 将 l 移动到 r 的位置,开始一个新的序列
l = r;
}
}
// 返回最终找到的最长非严格递增连续数字序列的长度
return maxLen;
}
}
代码逻辑详解
-
输入处理:
- 使用
Scanner
从控制台读取输入的字符串。 - 调用
getResult
方法计算最长非严格递增连续数字序列的长度。
- 使用
-
双指针初始化:
l
和r
分别表示当前数字序列的起始位置和结束位置,初始值均为 0。maxLen
用于记录当前找到的最长非严格递增连续数字序列的长度,初始值为 0。
-
遍历字符串:
- 使用
while
循环遍历字符串,r
指针从 0 开始逐步向右移动。 - 对于每个字符
c
,判断其是否是数字:- 如果是数字,则进一步判断是否满足非严格递增的条件。
- 如果不是数字,则记录当前数字序列的长度,并重置
l
和r
的位置。
- 使用
-
处理数字字符:
- 如果
l
和r
不在同一个位置,说明当前正在处理一个数字序列:- 判断当前字符是否大于等于前一个字符(非严格递增)。
- 如果是非严格递增,则更新当前序列的长度(
r - l + 1
),并更新maxLen
。 - 如果不是非严格递增,则记录当前序列的长度(
r - l
),并更新maxLen
,同时将l
移动到r
的位置,开始一个新的数字序列。
- 如果
l
和r
在同一个位置,说明当前是一个新的数字序列,长度为 1,直接更新maxLen
。
- 如果
-
处理非数字字符:
- 如果当前字符不是数字,则记录当前数字序列的长度(
r - l
),并更新maxLen
。 - 将
l
和r
移动到下一个字符的位置,开始一个新的序列。
- 如果当前字符不是数字,则记录当前数字序列的长度(
-
返回结果:
- 遍历结束后,返回
maxLen
,即最长非严格递增连续数字序列的长度。
- 遍历结束后,返回
示例运行
以输入 abc2234019A334bc
为例:
- 遍历到
2
时,开始一个新的数字序列,长度为 1。 - 遍历到
2
时,满足非严格递增,序列长度变为 2。 - 遍历到
3
时,满足非严格递增,序列长度变为 3。 - 遍历到
4
时,满足非严格递增,序列长度变为 4。 - 遍历到
0
时,不满足非严格递增,记录当前序列长度 4,并开始新的序列。 - 遍历到
1
时,开始新的序列,长度为 1。 - 遍历到
9
时,满足非严格递增,序列长度变为 2。 - 遍历到
A
时,记录当前序列长度 2,并开始新的序列。 - 遍历到
3
时,开始新的序列,长度为 1。 - 遍历到
3
时,满足非严格递增,序列长度变为 2。 - 遍历到
4
时,满足非严格递增,序列长度变为 3。 - 遍历到
b
时,记录当前序列长度 3,并开始新的序列。 - 遍历到
c
时,记录当前序列长度 0。
最终,最长非严格递增连续数字序列的长度为 4(2234
)。
总结
这段代码通过双指针的方法,高效地遍历字符串,动态维护当前数字序列的起始和结束位置,并在遇到字母或不满足条件的数字时,及时更新最长序列的长度。代码逻辑清晰,能够正确处理各种边界情况。
四、Python算法源码
以下是 Python 代码的详细注释和讲解,帮助理解每一部分的作用和逻辑:
代码讲解
# 输入获取
s = input()
# 算法入口
def getResult():
# 初始化双指针 l 和 r,分别表示当前数字序列的起始位置和结束位置
l = 0
r = 0
# 初始化 maxLen,用于记录当前找到的最长非严格递增连续数字序列的长度
maxLen = 0
# 遍历字符串
while r < len(s):
# 判断当前字符是否是数字
if '0' <= s[r] <= '9':
# 如果 l 和 r 不在同一个位置,说明当前正在处理一个数字序列
if l != r:
# 判断当前字符是否大于等于前一个字符(非严格递增)
if s[r] >= s[r-1]:
# 如果是非严格递增,则更新当前序列的长度(r - l + 1),并更新 maxLen
maxLen = max(maxLen, r - l + 1)
# 移动 r 指针,继续检查下一个字符
r += 1
else:
# 如果不是非严格递增,则记录当前序列的长度(r - l),并更新 maxLen
maxLen = max(maxLen, r - l)
# 将 l 移动到 r 的位置,开始一个新的数字序列
l = r
# 移动 r 指针,继续检查下一个字符
r += 1
else:
# 如果 l 和 r 在同一个位置,说明当前是一个新的数字序列,长度为 1
maxLen = max(maxLen, 1)
# 移动 r 指针,继续检查下一个字符
r += 1
else:
# 如果当前字符不是数字,则记录当前数字序列的长度(r - l),并更新 maxLen
maxLen = max(maxLen, r - l)
# 移动 r 指针到下一个字符
r += 1
# 将 l 移动到 r 的位置,开始一个新的序列
l = r
# 返回最终找到的最长非严格递增连续数字序列的长度
return maxLen
# 调用算法
print(getResult())
代码逻辑详解
-
输入处理:
- 使用
input()
函数从控制台读取输入的字符串。
- 使用
-
双指针初始化:
l
和r
分别表示当前数字序列的起始位置和结束位置,初始值均为 0。maxLen
用于记录当前找到的最长非严格递增连续数字序列的长度,初始值为 0。
-
遍历字符串:
- 使用
while
循环遍历字符串,r
指针从 0 开始逐步向右移动。 - 对于每个字符
s[r]
,判断其是否是数字:- 如果是数字,则进一步判断是否满足非严格递增的条件。
- 如果不是数字,则记录当前数字序列的长度,并重置
l
和r
的位置。
- 使用
-
处理数字字符:
- 如果
l
和r
不在同一个位置,说明当前正在处理一个数字序列:- 判断当前字符是否大于等于前一个字符(非严格递增)。
- 如果是非严格递增,则更新当前序列的长度(
r - l + 1
),并更新maxLen
。 - 如果不是非严格递增,则记录当前序列的长度(
r - l
),并更新maxLen
,同时将l
移动到r
的位置,开始一个新的数字序列。
- 如果
l
和r
在同一个位置,说明当前是一个新的数字序列,长度为 1,直接更新maxLen
。
- 如果
-
处理非数字字符:
- 如果当前字符不是数字,则记录当前数字序列的长度(
r - l
),并更新maxLen
。 - 将
l
和r
移动到下一个字符的位置,开始一个新的序列。
- 如果当前字符不是数字,则记录当前数字序列的长度(
-
返回结果:
- 遍历结束后,返回
maxLen
,即最长非严格递增连续数字序列的长度。
- 遍历结束后,返回
示例运行
以输入 abc2234019A334bc
为例:
- 遍历到
2
时,开始一个新的数字序列,长度为 1。 - 遍历到
2
时,满足非严格递增,序列长度变为 2。 - 遍历到
3
时,满足非严格递增,序列长度变为 3。 - 遍历到
4
时,满足非严格递增,序列长度变为 4。 - 遍历到
0
时,不满足非严格递增,记录当前序列长度 4,并开始新的序列。 - 遍历到
1
时,开始新的序列,长度为 1。 - 遍历到
9
时,满足非严格递增,序列长度变为 2。 - 遍历到
A
时,记录当前序列长度 2,并开始新的序列。 - 遍历到
3
时,开始新的序列,长度为 1。 - 遍历到
3
时,满足非严格递增,序列长度变为 2。 - 遍历到
4
时,满足非严格递增,序列长度变为 3。 - 遍历到
b
时,记录当前序列长度 3,并开始新的序列。 - 遍历到
c
时,记录当前序列长度 0。
最终,最长非严格递增连续数字序列的长度为 4(2234
)。
总结
这段 Python 代码通过双指针的方法,高效地遍历字符串,动态维护当前数字序列的起始和结束位置,并在遇到字母或不满足条件的数字时,及时更新最长序列的长度。代码逻辑清晰,能够正确处理各种边界情况。
五、C/C++算法源码:
以下是 C++ 和 C语言 代码的中文详细注释和讲解,帮助理解每一部分的作用和逻辑:
C++ 代码
#include <iostream>
#include <string>
using namespace std;
// 定义宏 MAX,用于比较两个数的大小并返回较大的值
#define MAX(a, b) (a > b ? a : b)
int main() {
// 定义字符串 s,用于存储输入的字符串
string s;
// 使用 cin 从控制台读取输入的字符串
cin >> s;
// 初始化双指针 l 和 r,分别表示当前数字序列的起始位置和结束位置
int l = 0;
int r = 0;
// 初始化 maxLen,用于记录当前找到的最长非严格递增连续数字序列的长度
int maxLen = 0;
// 遍历字符串
while (r < s.length()) {
// 获取当前字符
char c = s[r];
// 判断当前字符是否是数字
if (c >= '0' && c <= '9') {
// 如果 l 和 r 不在同一个位置,说明当前正在处理一个数字序列
if (l != r) {
// 判断当前字符是否大于等于前一个字符(非严格递增)
if (c >= s[r - 1]) {
// 如果是非严格递增,则更新当前序列的长度(r - l + 1),并更新 maxLen
maxLen = MAX(maxLen, r - l + 1);
} else {
// 如果不是非严格递增,则记录当前序列的长度(r - l),并更新 maxLen
maxLen = MAX(maxLen, r - l);
// 将 l 移动到 r 的位置,开始一个新的数字序列
l = r;
}
// 移动 r 指针,继续检查下一个字符
r++;
} else {
// 如果 l 和 r 在同一个位置,说明当前是一个新的数字序列,长度为 1
maxLen = MAX(maxLen, 1);
// 移动 r 指针,继续检查下一个字符
r++;
}
} else {
// 如果当前字符不是数字,则记录当前数字序列的长度(r - l),并更新 maxLen
maxLen = MAX(maxLen, r - l);
// 移动 r 指针到下一个字符
r++;
// 将 l 移动到 r 的位置,开始一个新的序列
l = r;
}
}
// 输出最终找到的最长非严格递增连续数字序列的长度
cout << maxLen << endl;
return 0;
}
C 语言代码
#include <stdio.h>
#include <string.h>
// 定义宏 MAX,用于比较两个数的大小并返回较大的值
#define MAX(a, b) (a > b ? a : b)
int main() {
// 定义字符数组 s,用于存储输入的字符串,最大长度为 255
char s[255];
// 使用 scanf 从控制台读取输入的字符串
scanf("%s", s);
// 初始化双指针 l 和 r,分别表示当前数字序列的起始位置和结束位置
int l = 0;
int r = 0;
// 初始化 maxLen,用于记录当前找到的最长非严格递增连续数字序列的长度
int maxLen = 0;
// 遍历字符串
while (r < strlen(s)) {
// 获取当前字符
char c = s[r];
// 判断当前字符是否是数字
if (c >= '0' && c <= '9') {
// 如果 l 和 r 不在同一个位置,说明当前正在处理一个数字序列
if (l != r) {
// 判断当前字符是否大于等于前一个字符(非严格递增)
if (c >= s[r - 1]) {
// 如果是非严格递增,则更新当前序列的长度(r - l + 1),并更新 maxLen
maxLen = MAX(maxLen, r - l + 1);
} else {
// 如果不是非严格递增,则记录当前序列的长度(r - l),并更新 maxLen
maxLen = MAX(maxLen, r - l);
// 将 l 移动到 r 的位置,开始一个新的数字序列
l = r;
}
// 移动 r 指针,继续检查下一个字符
r++;
} else {
// 如果 l 和 r 在同一个位置,说明当前是一个新的数字序列,长度为 1
maxLen = MAX(maxLen, 1);
// 移动 r 指针,继续检查下一个字符
r++;
}
} else {
// 如果当前字符不是数字,则记录当前数字序列的长度(r - l),并更新 maxLen
maxLen = MAX(maxLen, r - l);
// 移动 r 指针到下一个字符
r++;
// 将 l 移动到 r 的位置,开始一个新的序列
l = r;
}
}
// 输出最终找到的最长非严格递增连续数字序列的长度
printf("%d\n", maxLen);
return 0;
}
代码逻辑详解
-
输入处理:
- C++: 使用
cin
从控制台读取输入的字符串。 - C: 使用
scanf
从控制台读取输入的字符串。
- C++: 使用
-
双指针初始化:
l
和r
分别表示当前数字序列的起始位置和结束位置,初始值均为 0。maxLen
用于记录当前找到的最长非严格递增连续数字序列的长度,初始值为 0。
-
遍历字符串:
- 使用
while
循环遍历字符串,r
指针从 0 开始逐步向右移动。 - 对于每个字符
s[r]
,判断其是否是数字:- 如果是数字,则进一步判断是否满足非严格递增的条件。
- 如果不是数字,则记录当前数字序列的长度,并重置
l
和r
的位置。
- 使用
-
处理数字字符:
- 如果
l
和r
不在同一个位置,说明当前正在处理一个数字序列:- 判断当前字符是否大于等于前一个字符(非严格递增)。
- 如果是非严格递增,则更新当前序列的长度(
r - l + 1
),并更新maxLen
。 - 如果不是非严格递增,则记录当前序列的长度(
r - l
),并更新maxLen
,同时将l
移动到r
的位置,开始一个新的数字序列。
- 如果
l
和r
在同一个位置,说明当前是一个新的数字序列,长度为 1,直接更新maxLen
。
- 如果
-
处理非数字字符:
- 如果当前字符不是数字,则记录当前数字序列的长度(
r - l
),并更新maxLen
。 - 将
l
和r
移动到下一个字符的位置,开始一个新的序列。
- 如果当前字符不是数字,则记录当前数字序列的长度(
-
输出结果:
- C++: 使用
cout
输出结果。 - C: 使用
printf
输出结果。
- C++: 使用
示例运行
以输入 abc2234019A334bc
为例:
- 遍历到
2
时,开始一个新的数字序列,长度为 1。 - 遍历到
2
时,满足非严格递增,序列长度变为 2。 - 遍历到
3
时,满足非严格递增,序列长度变为 3。 - 遍历到
4
时,满足非严格递增,序列长度变为 4。 - 遍历到
0
时,不满足非严格递增,记录当前序列长度 4,并开始新的序列。 - 遍历到
1
时,开始新的序列,长度为 1。 - 遍历到
9
时,满足非严格递增,序列长度变为 2。 - 遍历到
A
时,记录当前序列长度 2,并开始新的序列。 - 遍历到
3
时,开始新的序列,长度为 1。 - 遍历到
3
时,满足非严格递增,序列长度变为 2。 - 遍历到
4
时,满足非严格递增,序列长度变为 3。 - 遍历到
b
时,记录当前序列长度 3,并开始新的序列。 - 遍历到
c
时,记录当前序列长度 0。
最终,最长非严格递增连续数字序列的长度为 4(2234
)。
总结
- C++ 和 C 代码逻辑一致,均通过双指针的方法高效地遍历字符串。
- 动态维护当前数字序列的起始和结束位置,并在遇到字母或不满足条件的数字时,及时更新最长序列的长度。
- 代码逻辑清晰,能够正确处理各种边界情况。
单指针解法
解法逻辑
-
初始化变量:
- 使用一个变量
len
来记录当前非严格递增连续数字序列的长度。 - 使用一个变量
maxNum
来记录当前序列中最大的数字字符。 - 使用一个变量
maxLen
来记录全局最长非严格递增连续数字序列的长度。
- 使用一个变量
-
遍历字符串:
- 从左到右逐个扫描字符串中的字符。
-
遇到字母时:
- 如果当前字符是字母,则重置
len
和maxNum
:len = 0
,表示当前序列长度为0。maxNum = 0
,表示当前序列中最大的数字字符为0。
- 如果当前字符是字母,则重置
-
遇到数字时:
- 如果
len
为0,说明当前数字是序列的开头:- 设置
len = 1
,表示当前序列长度为1。 - 设置
maxNum
为当前数字字符的值。
- 设置
- 如果
len
不为0,说明当前数字前面还有数字:- 判断当前数字是否大于等于
maxNum
:- 如果是,则当前序列可以继续延长,
len++
,并更新maxNum
为当前数字字符的值。 - 如果不是,则当前序列中断,重置
len = 1
,并更新maxNum
为当前数字字符的值。
- 如果是,则当前序列可以继续延长,
- 判断当前数字是否大于等于
- 每次更新
len
后,检查是否需要更新maxLen
。
- 如果
-
结束遍历:
- 遍历结束后,
maxLen
即为最长非严格递增连续数字序列的长度。
- 遍历结束后,
示例运行
以输入 abc2234019A334bc
为例:
- 遍历到
2
时:len = 1
,maxNum = 2
,maxLen = 1
。
- 遍历到
2
时:- 当前数字
2
大于等于maxNum
,len++
,maxNum = 2
,maxLen = 2
。
- 当前数字
- 遍历到
3
时:- 当前数字
3
大于等于maxNum
,len++
,maxNum = 3
,maxLen = 3
。
- 当前数字
- 遍历到
4
时:- 当前数字
4
大于等于maxNum
,len++
,maxNum = 4
,maxLen = 4
。
- 当前数字
- 遍历到
0
时:- 当前数字
0
小于maxNum
,重置len = 1
,maxNum = 0
,maxLen
仍为4。
- 当前数字
- 遍历到
1
时:- 当前数字
1
大于等于maxNum
,len++
,maxNum = 1
,maxLen
仍为4。
- 当前数字
- 遍历到
9
时:- 当前数字
9
大于等于maxNum
,len++
,maxNum = 9
,maxLen
仍为4。
- 当前数字
- 遍历到
A
时:- 当前字符是字母,重置
len = 0
,maxNum = 0
,maxLen
仍为4。
- 当前字符是字母,重置
- 遍历到
3
时:len = 1
,maxNum = 3
,maxLen
仍为4。
- 遍历到
3
时:- 当前数字
3
大于等于maxNum
,len++
,maxNum = 3
,maxLen
仍为4。
- 当前数字
- 遍历到
4
时:- 当前数字
4
大于等于maxNum
,len++
,maxNum = 4
,maxLen
仍为4。
- 当前数字
- 遍历到
b
时:- 当前字符是字母,重置
len = 0
,maxNum = 0
,maxLen
仍为4。
- 当前字符是字母,重置
- 遍历到
c
时:- 当前字符是字母,重置
len = 0
,maxNum = 0
,maxLen
仍为4。
- 当前字符是字母,重置
最终,最长非严格递增连续数字序列的长度为 4(2234
)。
总结
- 单指针解法通过一个变量
len
记录当前序列的长度,另一个变量maxNum
记录当前序列中最大的数字字符。 - 每次遇到数字时,根据当前数字与
maxNum
的关系更新len
和maxNum
,并实时更新全局最大值maxLen
。 - 该解法避免了双指针的繁琐逻辑,代码更加简洁高效。
以下是 Java、JavaScript、Python 和 C 四种语言的代码详细注释和讲解,帮助理解每一部分的作用和逻辑:
Java 代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 创建 Scanner 对象,用于从控制台读取输入
Scanner sc = new Scanner(System.in);
// 读取输入的字符串
String s = sc.nextLine();
// 调用 getResult 方法,计算最长非严格递增连续数字序列的长度,并输出结果
System.out.println(getResult(s));
}
public static int getResult(String s) {
// 初始化变量 maxNum,用于记录当前数字序列中的最大数字
int maxNum = 0;
// 初始化变量 len,用于记录当前非严格递增连续数字序列的长度
int len = 0;
// 初始化变量 maxLen,用于记录全局最长非严格递增连续数字序列的长度
int maxLen = 0;
// 遍历字符串
for (int i = 0; i < s.length(); i++) {
// 获取当前字符
char c = s.charAt(i);
// 判断当前字符是否是数字
if (c >= '0' && c <= '9') {
// 将字符转换为对应的数字值
int curNum = c - '0';
// 如果 len 为 0,说明当前数字是序列的开头
if (len == 0) {
// 设置当前序列长度为 1
len = 1;
// 更新 maxNum 为当前数字
maxNum = curNum;
} else {
// 如果 len 不为 0,说明当前数字前面还有数字
// 判断当前数字是否大于等于 maxNum(非严格递增)
if (curNum >= maxNum) {
// 如果是非严格递增,则当前序列长度加 1
len++;
} else {
// 如果不是非严格递增,则重置当前序列长度为 1
len = 1;
}
// 更新 maxNum 为当前数字
maxNum = curNum;
}
} else {
// 如果当前字符不是数字,则重置 len 和 maxNum
len = 0;
maxNum = 0;
}
// 更新全局最长非严格递增连续数字序列的长度
maxLen = Math.max(maxLen, len);
}
// 返回最终找到的最长非严格递增连续数字序列的长度
return maxLen;
}
}
JavaScript 代码
/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");
// 创建 readline 接口,用于从控制台读取输入
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 监听 'line' 事件,当用户输入一行内容时触发
rl.on("line", (line) => {
// 调用 getMaxLen 函数,计算最长非严格递增连续数字序列的长度,并输出结果
console.log(getMaxLen(line));
});
function getMaxLen(str) {
// 初始化变量 maxLen,用于记录全局最长非严格递增连续数字序列的长度
let maxLen = 0;
// 初始化变量 len,用于记录当前非严格递增连续数字序列的长度
let len = 0;
// 初始化变量 maxNum,用于记录当前数字序列中的最大数字
let maxNum = 0;
// 遍历字符串
for (let i = 0; i < str.length; i++) {
// 判断当前字符是否是数字
if (/\d/.test(str[i])) {
// 将字符转换为对应的数字值
let curNum = str[i] - 0;
// 如果 len 为 0,说明当前数字是序列的开头
if (len === 0) {
// 设置当前序列长度为 1
len = 1;
// 更新 maxNum 为当前数字
maxNum = curNum;
} else {
// 如果 len 不为 0,说明当前数字前面还有数字
// 判断当前数字是否大于等于 maxNum(非严格递增)
if (curNum >= maxNum) {
// 如果是非严格递增,则当前序列长度加 1
len++;
} else {
// 如果不是非严格递增,则重置当前序列长度为 1
len = 1;
}
// 更新 maxNum 为当前数字
maxNum = curNum;
}
} else {
// 如果当前字符不是数字,则重置 len 和 maxNum
len = 0;
maxNum = 0;
}
// 更新全局最长非严格递增连续数字序列的长度
maxLen = Math.max(maxLen, len);
}
// 返回最终找到的最长非严格递增连续数字序列的长度
return maxLen;
}
Python 代码
# 输入获取
s = input()
# 算法入口
def getResult():
# 初始化变量 maxLen,用于记录全局最长非严格递增连续数字序列的长度
maxLen = 0
# 初始化变量 length,用于记录当前非严格递增连续数字序列的长度
length = 0
# 初始化变量 maxNum,用于记录当前数字序列中的最大数字
maxNum = 0
# 遍历字符串
for c in s:
# 判断当前字符是否是数字
if '0' <= c <= '9':
# 将字符转换为对应的数字值
curNum = int(c)
# 如果 length 为 0,说明当前数字是序列的开头
if length == 0:
# 设置当前序列长度为 1
length = 1
# 更新 maxNum 为当前数字
maxNum = curNum
else:
# 如果 length 不为 0,说明当前数字前面还有数字
# 判断当前数字是否大于等于 maxNum(非严格递增)
if curNum >= maxNum:
# 如果是非严格递增,则当前序列长度加 1
length += 1
else:
# 如果不是非严格递增,则重置当前序列长度为 1
length = 1
# 更新 maxNum 为当前数字
maxNum = curNum
else:
# 如果当前字符不是数字,则重置 length 和 maxNum
length = 0
maxNum = 0
# 更新全局最长非严格递增连续数字序列的长度
maxLen = max(maxLen, length)
# 返回最终找到的最长非严格递增连续数字序列的长度
return maxLen
# 调用算法
print(getResult())
C 代码
#include <stdio.h>
#include <string.h>
// 定义宏 MAX,用于比较两个数的大小并返回较大的值
#define MAX(a, b) a > b ? a : b
int main() {
// 定义字符数组 s,用于存储输入的字符串,最大长度为 255
char s[255];
// 使用 scanf 从控制台读取输入的字符串
scanf("%s", s);
// 初始化变量 maxNum,用于记录当前数字序列中的最大数字
int maxNum = 0;
// 初始化变量 len,用于记录当前非严格递增连续数字序列的长度
int len = 0;
// 初始化变量 maxLen,用于记录全局最长非严格递增连续数字序列的长度
int maxLen = 0;
// 遍历字符串
for (int i = 0; i < strlen(s); i++) {
// 判断当前字符是否是数字
if (s[i] >= '0' && s[i] <= '9') {
// 将字符转换为对应的数字值
int curNum = s[i] - '0';
// 如果 len 为 0,说明当前数字是序列的开头
if (len == 0) {
// 设置当前序列长度为 1
len = 1;
// 更新 maxNum 为当前数字
maxNum = curNum;
} else {
// 如果 len 不为 0,说明当前数字前面还有数字
// 判断当前数字是否大于等于 maxNum(非严格递增)
if (curNum >= maxNum) {
// 如果是非严格递增,则当前序列长度加 1
len++;
} else {
// 如果不是非严格递增,则重置当前序列长度为 1
len = 1;
}
// 更新 maxNum 为当前数字
maxNum = curNum;
}
} else {
// 如果当前字符不是数字,则重置 len 和 maxNum
len = 0;
maxNum = 0;
}
// 更新全局最长非严格递增连续数字序列的长度
maxLen = MAX(maxLen, len);
}
// 输出最终找到的最长非严格递增连续数字序列的长度
printf("%d", maxLen);
return 0;
}
总结
- Java、JavaScript、Python 和 C 四种语言的代码逻辑完全一致。
- 通过单指针的方法,动态维护当前数字序列的长度和最大数字字符。
- 每次遇到数字时,根据当前数字与
maxNum
的关系更新len
和maxNum
,并实时更新全局最大值maxLen
。 - 代码逻辑清晰,能够正确处理各种边界情况。
六、尾言
什么是华为OD?
华为OD(Outsourcing Developer,外包开发工程师)是华为针对软件开发工程师岗位的一种招聘形式,主要包括笔试、技术面试以及综合面试等环节。尤其在笔试部分,算法题的机试至关重要。
为什么刷题很重要?
-
机试是进入技术面的第一关:
华为OD机试(常被称为机考)主要考察算法和编程能力。只有通过机试,才能进入后续的技术面试环节。 -
技术面试需要手撕代码:
技术一面和二面通常会涉及现场编写代码或算法题。面试官会注重考察候选人的思路清晰度、代码规范性以及解决问题的能力。因此提前刷题、多练习是通过面试的重要保障。 -
入职后的可信考试:
入职华为后,还需要通过“可信考试”。可信考试分为三个等级:- 入门级:主要考察基础算法与编程能力。
- 工作级:更贴近实际业务需求,可能涉及复杂的算法或与工作内容相关的场景题目。
- 专业级:最高等级,考察深层次的算法以及优化能力,与薪资直接挂钩。
刷题策略与说明:
2024年8月14日之后,华为OD机试的题库转为 E卷,由往年题库(D卷、A卷、B卷、C卷)和全新题目组成。刷题时可以参考以下策略:
-
关注历年真题:
- 题库中的旧题占比较大,建议优先刷历年的A卷、B卷、C卷、D卷题目。
- 对于每道题目,建议深度理解其解题思路、代码实现,以及相关算法的适用场景。
-
适应新题目:
- E卷中包含全新题目,需要掌握全面的算法知识和一定的灵活应对能力。
- 建议关注新的刷题平台或交流群,获取最新题目的解析和动态。
-
掌握常见算法:
华为OD考试通常涉及以下算法和数据结构:- 排序算法(快速排序、归并排序等)
- 动态规划(背包问题、最长公共子序列等)
- 贪心算法
- 栈、队列、链表的操作
- 图论(最短路径、最小生成树等)
- 滑动窗口、双指针算法
-
保持编程规范:
- 注重代码的可读性和注释的清晰度。
- 熟练使用常见编程语言,如C++、Java、Python等。
如何获取资源?
-
官方参考:
- 华为招聘官网或相关的招聘平台会有一些参考信息。
- 华为OD的相关公众号可能也会发布相关的刷题资料或学习资源。
-
加入刷题社区:
- 找到可信的刷题交流群,与其他备考的小伙伴交流经验。
- 关注知名的刷题网站,如LeetCode、牛客网等,这些平台上有许多华为OD的历年真题和解析。
-
寻找系统性的教程:
- 学习一本经典的算法书籍,例如《算法导论》《剑指Offer》《编程之美》等。
- 完成系统的学习课程,例如数据结构与算法的在线课程。
积极心态与持续努力:
刷题的过程可能会比较枯燥,但它能够显著提升编程能力和算法思维。无论是为了通过华为OD的招聘考试,还是为了未来的职业发展,这些积累都会成为重要的财富。
考试注意细节
-
本地编写代码
- 在本地 IDE(如 VS Code、PyCharm 等)上编写、保存和调试代码,确保逻辑正确后再复制粘贴到考试页面。这样可以减少语法错误,提高代码准确性。
-
调整心态,保持冷静
- 遇到提示不足或实现不确定的问题时,不必慌张,可以采用更简单或更有把握的方法替代,确保思路清晰。
-
输入输出完整性
- 注意训练和考试时都需要编写完整的输入输出代码,尤其是和题目示例保持一致。完成代码后务必及时调试,确保功能符合要求。
-
快捷键使用
- 删除行可用
Ctrl+D
,复制、粘贴和撤销分别为Ctrl+C
,Ctrl+V
,Ctrl+Z
,这些可以正常使用。 - 避免使用
Ctrl+S
,以免触发浏览器的保存功能。
- 删除行可用
-
浏览器要求
- 使用最新版的 Google Chrome 浏览器完成考试,确保摄像头开启并正常工作。考试期间不要切换到其他网站,以免影响考试成绩。
-
交卷相关
- 答题前,务必仔细查看题目示例,避免遗漏要求。
- 每完成一道题后,点击【保存并调试】按钮,多次保存和调试是允许的,系统会记录得分最高的一次结果。完成所有题目后,点击【提交本题型】按钮。
- 确保在考试结束前提交试卷,避免因未保存或调试失误而丢分。
-
时间和分数安排
- 总时间:150 分钟;总分:400 分。
- 试卷结构:2 道一星难度题(每题 100 分),1 道二星难度题(200 分)。及格分为 150 分。合理分配时间,优先完成自己擅长的题目。
-
考试环境准备
- 考试前请备好草稿纸和笔。考试中尽量避免离开座位,确保监控画面正常。
- 如需上厕所,请提前规划好时间以减少中途离开监控的可能性。
-
技术问题处理
- 如果考试中遇到断电、断网、死机等技术问题,可以关闭浏览器并重新打开试卷链接继续作答。
- 出现其他问题,请第一时间联系 HR 或监考人员进行反馈。
祝你考试顺利,取得理想成绩!