华为不同职级 薪资待遇一览表。。。

来源:互联网 时间:2025-11-06 04:12:35 浏览量:0

大家好,我是吴师兄。

最近看到一张华为不同职级的薪资待遇表,不得不说,真的是让人看了心动又焦虑。

对于我们这些职场小白来说,华为的职级体系和薪资待遇就像是职业生涯的一个“终极目标”,但这也意味着:有多少人能从13级做到20级?

华为的职级从 13 级到 22 级,23 级及以上是高层管理人员,普通员工最多也就能升到 20 级。

每一级的薪资差距非常明显,而且更高等级的薪资数据几乎是“神秘”状态。最有意思的是, 华为的每个职级分为A/B/C三个小级别,但技术岗位并不细分等级

这就意味着,不同岗位的晋升速度和难度差距也挺大。

我从朋友那里得知,华为的16级已经是技术骨干的级别,18级基本上就是“技术专家”的身份了。

到了19、20级,年薪直接突破百万!这是常规岗位无法想象的数字,但这背后是否隐藏着更高的压力和挑战呢?

来看看华为 13 级到 20 级的薪资待遇表——

  • 13级基本工资20.8万,年终奖3.4万,股权激励0,年薪大概24.2万。

  • 14级基本工资28.8万,年终奖5.8万,股权激励0.3万,年薪大概34.9万。

  • 15级基本工资31.5万,年终奖10万,股权激励3万,年薪大概44.5万。

  • 16级基本工资42万,年终奖13.5万,股权激励8.5万,年薪大概64万。

  • 17级基本工资50万,年终奖19.5万,股权激励18.6万,年薪大概88.1万。

  • 18级基本工资72万,年终奖40.7万,股权激励27.2万,年薪大概139.9万。

  • 19级基本工资75.1万,年终奖63.5万,股权激励22万,年薪大概160.6万。

  • 20级基本工资60.5万,年终奖75万,股权激励125.8万,年薪大概261.3万。

可以看到, 薪资差距堪称“天壤之别”

13级的年薪才24.2万,而20级则已经突破了260万!这差距不仅仅是数字上的变化,更是在于职场地位、影响力、责任的巨大差异。

但你会发现,华为的职级晋升不光看能力,还要有一定的运气成分。

16级到18级是一个关键节点,18级更是技术专家的标志,意味着你已经在行业内有了话语权。

但问题是,能做到这一点的人究竟有多少?有些人可能刚进华为就被卡在13级,做了一辈子基础工作;有些人则通过自己的努力,爬到了16级以上,年薪翻了几倍,简直“逆袭人生”。

很多人都说, “在华为,选择和努力同样重要”。确实,很多人从13级走到16级、18级,不仅仅是因为他们有技术,更是因为他们抓住了机会,迎合了市场需求,甚至有运气成分在内。

可问题是,能抓住机会的那些人, 大多都是那些站在行业风口浪尖的人。而我们这些普通员工,或许就会因为一个偶然的失误,被卡在低职级,难以晋升。

回归我们公众号的主题, 每天掌握一道算法题

继续来一道和「华为校招」相关的算法原题。

本原题练习网址:https://www.algomooc.com/problem/P3004

题目描述

跳房子,也叫跳飞机,是一种世界性的儿童游戏。

游戏参与者需要分多个回合按顺序跳到第1格直到房子的最后一格,然后获得一次选房子的机会,直到所有房子都被选完,房子最多的人获胜。

跳房子的过程中,如果有踩线等违规行为会结束当前回合,甚至可能倒退几步。

假设房子的总格数是count,小红每回合可能连续跳的步数都放在数据steps中,请问数组中是否有一种步数的组合,可以让小红三个回合跳到最后一格?如果有,请输出索引和最小的步数组合,数据保证索引和最小的步数组合是唯一的。

注意:数组中的步数可以重复,但数组中的元素不能重复使用。

输入描述

第一行输入为房子总格数count,它是整数类型int。

第二行输入为每回合可能连续跳过的步数,它是整数数组类型。

输出描述

返回索引和最小满足要求的步数组合。

注意:顺序保持steps中的原有顺序。

备注

  • count <= 10000;

  • 3 <= steps.length <= 10000;

示例一输入1,4,5,2,0,2

9

输出4,5,0

说明示例二输入1,5,2,0,2,4

9

输出5,2,2

示例三输入-1,2,4,9

12

输出-1,4,9

解题思路

注意,本题和LeetCode15、三数之和基本完全一致。区别仅仅在于本题需要找到下标和最小的索引。

首先要理解题意。

输出描述的断句是这样的: 返回索引和最小(且)满足要求的步数组合

索引和一词是一个整体,表示需要找到三个数的索引的总和。

数组排序

在LeetCode15、三数之和 中我们知道,要使用双指针算法,我们必须对原数组进行从小到大的排序。

但是在本题中,一旦对原数组进行排序,那么其原来的索引就丢失了。

因此,我们在排序的过程中,除了对已知数据num进行排序,还必须同时储存每一个元素在原输入数组lst中的索引idx。故排序过程如下

# 对原nums数组进行排序,同时需要记录在原数组中的下标idx,作为排序的第二个依据

nums = sorted((num, idx) foridx, num inenumerate(lst))

注意此处我们新建的nums是一个二维数组,其中的内层元素(num, idx)是一个二元组,其中num是元素值,idx是num在原输入数组lst中的索引。

nums的中元素的排序,会先按照num的大小进行从小到大排序,当num相等时,则按照其出现在lst中的索引idx进行从小到大排序。

譬如对于例子

lst = [ 2, 5, 2, 5, 1, 4]

我们会得到

nums = [( 1, 4), ( 2, 0), ( 2, 2), ( 4, 5), ( 5, 1), ( 5, 3)]

双指针过程

接下来是非常经典的双指针过程。

对于nums中的元素,我们遍历里面里面的每一组(num, idx)(其在nums中的索引值为i),将其固定为选择的第一个元素。

而剩余的第二个元素和第三个元素,分别设置left和right从i+1和n-1的位置从两边往中间靠拢。

代码框架如下

# 考虑第一个数first

fori, (first, idx) inenumerate(nums[: -2]):

# 如果发现第i、第i+1、第i+2个数的和加起来超过target

# 则更靠后的的选择肯定和更大,直接退出循环

ifnums[i][ 0] + nums[i+ 1][ 0] + nums[i+ 2][ 0] > target:

break

# 去重操作,如果遇到连续两个数相等,那么考虑nums[i]和考虑nums[i-1]所作的计算是一样的

# 直接跳过nums[i]的计算

ifi != 0andnums[i][ 0] == nums[i -1][ 0]:

continue

# 构建相向双指针left和right

left, right = i+ 1, n -1

# 双指针过程

whileleft < right:

pass

接下来就是填充双指针过程,即上述代码框架中的while循环。

我们令当前的三数之和为sum3 = first + nums[left][0] + nums[right][0]。当

  • sum3 > target时,三数之和太大, sum3需要减小, right左移

  • sum3 < target时,三数之和太小, sum3需要增加, left右移

  • sum3 == target时,此时所选择的三个数的和为题目输入的目标和 target,我们需要更新答案。同时只有 right左移。

此处需要特别讨论,为什么在sum3 == target的时候,我们的代码中只有right左移,而不是left右移或者left和right同时移动。

在LeetCode15、三数之和 中,由于我们要找的是 元素组合,而不是 元素的索引组合,因此我们无论写成left右移、right左移还是left和right同时移动,答案都是正确的。

这三种写法,都能够避免while的死循环(也是这里指针移动的唯一作用)。

这是因为,只需要保证while中的每一个if分支中,至少有一个指针是在变化的,那么while中的left < right条件就一定会有不成立的时候,会顺利退出循环。

但是在本题中,由于我们要找的是元素的索引组合,并且要求是找到 索引和最小的索引组合

可能会存在一种情况,即nums[right-1][0] == nums[right][0]。

由于当num相等时元素按照在原数组中的索引idx进行从小到大排序,此时必然存在nums[right-1][1] < nums[right][1]。

譬如数组

nums = [( 1, 4), ( 2, 0), ( 2, 2), ( 4, 5), ( 5, 1), ( 5, 3)]

假设target = 9,当i = 1,left = 2,right = 5时,我们已经找到了(2, 0), (2, 2), (5, 3)这三个元素它们的数字和为target,索引和为5。

由于nums[4][0] == nums[5][0] == 5。

如果此时我们移动了left,我们将会错过索引和更小的(2, 0), (2, 2), (5, 1)这样的组合(i = 1,left = 2,right = 4,索引和为3)。

所以当我们找到一组答案的时候,不能够移动left(即使这样在其他题目中的正确的),只能移动right。这样才能够 尽可能地找到更小的索引和

因此,整体的代码如下

# 考虑第一个数first

fori, (first, idx) inenumerate(nums[: -2]):

# 如果发现第i、第i+1、第i+2个数的和加起来超过target

# 则更靠后的的选择肯定和更大,直接退出循环

ifnums[i][ 0] + nums[i+ 1][ 0] + nums[i+ 2][ 0] > target:

break

# 去重操作,如果遇到连续两个数相等,那么考虑nums[i]和考虑nums[i-1]所作的计算是一样的

# 直接跳过nums[i]的计算

ifi != 0andnums[i][ 0] == nums[i -1][ 0]:

continue

# 构建相向双指针left和right

left, right = i+ 1, n -1

# 双指针过程

whileleft < right:

# 计算三个数的和

sum3 = first + nums[left][ 0] + nums[right][ 0]

# 三数和太大,right左移

ifsum3 > target:

right -= 1

# 三数和太小,left右移

elifsum3 < target:

left += 1

# 三数和等于target,如果三个下标和比之前记录过的三数下标和更小

# 则更新ans_idx

else:

ifsum(ans_idx) > idx + nums[left][ 1] + nums[right][ 1]:

ans_idx = [idx, nums[left][ 1], nums[right][ 1]]

# 注意此处,只需要写right -= 1就行,不需要加上left += 1

# 1. 只写right -= 1就可以保证代码不会陷入死循环

# 因为只需要保证每一个if分支中,至少有一个指针是在变化的(也就是我们选择的right)

# 那么while中的left < right条件就一定会有不成立的时候

# 2. 由于排序时先按照num大小排列,再按照num在原数组中的索引排列。

# 如果此时存在 nums[right-1][0] == nums[right][0]

# 那么nums[right-1][1]会小于nums[right][1]

# i, nums[left][1]和nums[right-1][1]可以构成更小的索引和

# 如果加上了left += 1,可能会漏算全局最小的索引和

right -= 1

代码Python# https://www.algomooc.com/problem/P3004

frommath importinf

# 输入原数组lst

lst = list(map(int, input.split( ",")))

# 输入目标和

target = int(input)

# 获得原数组长度n

n = len(lst)

# 对原nums数组进行排序,同时需要记录在原数组中的下标i,作为排序的第二个依据

nums = sorted((num, idx) foridx, num inenumerate(lst))

# 初始化一个长度为3的数组,用于储存三个数的下标,初始化均为inf

ans_idx = [inf, inf, inf]

# 考虑第一个数first

fori, (first, idx) inenumerate(nums[: -2]):

# 如果发现第i、第i+1、第i+2个数的和加起来超过target

# 则更靠后的的选择肯定和更大,直接退出循环

ifnums[i][ 0] + nums[i+ 1][ 0] + nums[i+ 2][ 0] > target:

break

# 去重操作,如果遇到连续两个数相等,那么考虑nums[i]和考虑nums[i-1]作为第一个数字

# 所作的计算是一样的。直接跳过nums[i]的计算

ifi != 0andnums[i][ 0] == nums[i -1][ 0]:

continue

# 构建相向双指针left和right

left, right = i+ 1, n -1

whileleft < right:

# 计算三个数的和

sum3 = first + nums[left][ 0] + nums[right][ 0]

# 三数和太大,right左移

ifsum3 > target:

right -= 1

# 三数和太小,left右移

elifsum3 < target:

left += 1

# 三数和等于target,如果三个下标和比之前记录过的三数下标和更小

# 则更新ans_idx

else:

ifsum(ans_idx) > idx + nums[left][ 1] + nums[right][ 1]:

ans_idx = [idx, nums[left][ 1], nums[right][ 1]]

# 注意此处,只需要写right -= 1就行,不需要加上left += 1

# 1. 只写right -= 1就可以保证代码不会陷入死循环

# 因为只需要保证每一个if分支中,至少有一个指针是在变化的(也就是我们选择的right)

# 那么while中的left < right条件就一定会有不成立的时候

# 2. 由于排序时先按照num大小排列,再按照num在原数组中的索引排列。

# 如果此时存在 nums[right-1][0] == nums[right][0]

# 那么nums[right-1][1]会小于nums[right][1]

# i, nums[left][1]和nums[right-1][1]可以构成更小的索引和

# 如果加上了left += 1,可能会漏算全局最小的索引和

right -= 1

# 退出循环,ans_idx为在原数组中的三个数的下标

# 答案需要按照下标大小进行排列

ans_idx.sort

ans = ",".join(str(lst[idx]) foridx inans_idx)

print(ans)

Javaimportjava.util.*;

publicclassMain{

publicstaticvoidmain(String[] args){

Scanner scanner = newScanner(System.in);

// 读取一行包含逗号分隔数字的数组

String line = scanner.nextLine;

// 使用 StringTokenizer 分割数字

StringTokenizer tokenizer = newStringTokenizer(line, ",");

List<Integer> lst = newArrayList<>;

while(tokenizer.hasMoreTokens) {

lst.add(Integer.parseInt(tokenizer.nextToken));

}

// 读取下一行的数字

inttarget = scanner.nextInt;

// 获得原数组长度 n

intn = lst.size;

// 对原 nums 数组进行排序,同时需要记录在原数组中的下标 i,作为排序的第二个依据

List<Pair> nums = newArrayList<>;

for( inti = 0; i < n; i++) {

nums.add( newPair(lst.get(i), i));

}

Collections.sort(nums);

// 初始化一个长度为 3 的数组,用于储存三个数的下标,初始化均为 n

List<Integer> ansIdx = newArrayList<>(Arrays.asList(n, n, n));

// 考虑第一个数 first

for( inti = 0; i < n - 2; i++) {

// 如果发现第 i、第 i+1、第 i+2 个数的和加起来超过 target

// 则更靠后的选择肯定和更大,直接退出循环

if(nums.get(i).first + nums.get(i + 1).first + nums.get(i + 2).first > target) {

break;

}

// 去重操作,如果遇到连续两个数相等,那么考虑 nums[i] 和考虑 nums[i-1] 所作的计算是一样的

// 直接跳过 nums[i] 的计算

if(i != 0&& nums.get(i).first == nums.get(i - 1).first) {

continue;

}

// 构建相向双指针 left 和 right

intleft = i + 1, right = n - 1;

while(left < right) {

// 计算三个数的和

intsum3 = nums.get(i).first + nums.get(left).first + nums.get(right).first;

// 三数和太大,right 左移

if(sum3 > target) {

right--;

}

// 三数和太小,left 右移

elseif(sum3 < target) {

left++;

}

// 三数和等于 target,如果三个下标和比之前记录过的三数下标和更小

// 则更新 ansIdx

else{

if(ansIdx.get( 0) + ansIdx.get( 1) + ansIdx.get( 2) > nums.get(i).second + nums.get(left).second + nums.get(right).second) {

ansIdx = Arrays.asList(nums.get(i).second, nums.get(left).second, nums.get(right).second);

}

// 注意此处,只需要写 righ-- 就行,不需要加上 left++

// 1. 只写right -= 1就可以保证代码不会陷入死循环

// 因为只需要保证每一个if分支中,至少有一个指针是在变化的(也就是我们选择的right)

// 那么while中的left < right条件就一定会有不成立的时候

// 2. 由于排序时先按照num大小排列,再按照num在原数组中的索引排列。

// 如果此时存在 nums[right-1][0] == nums[right][0]

// 那么nums[right-1][1]会小于nums[right][1]

// i, nums[left][1]和nums[right-1][1]可以构成更小的索引和

// 如果加上了 left++ ,可能会漏算全局最小的索引和

right--;

}

}

}

// 退出循环,ansIdx 为在原数组中的三个数的下标

// 答案需要按照下标大小进行排列

Collections.sort(ansIdx);

for( inti = 0; i < 3; i++) {

System.out.print(lst.get(ansIdx.get(i)));

if(i < 2) {

System.out.print( ",");

}

}

System.out.println;

}

staticclassPairimplementsComparable< Pair> {

intfirst;

intsecond;

Pair( intfirst, intsecond) {

this.first = first;

this.second = second;

}

@Override

publicintcompareTo(Pair other){

returnInteger.compare( this.first, other.first);

}

}

}

C++# include<iostream>

# include<sstream>

# include<vector>

# include<algorithm>

# include<numeric>

usingnamespacestd;

intmain{

// 读取一行包含逗号分隔数字的数组

stringline;

getline( cin, line);

// 使用 stringstream 分割数字

stringstreamss(line);

vector< int> lst;

stringtoken;

while(getline(ss, token, ','))

{

lst.push_back(stoi(token));

}

// 读取下一行的数字

inttarget;

cin>> target;

// 获得原数组长度 n

intn = lst.size;

// 对原 nums 数组进行排序,同时需要记录在原数组中的下标 i,作为排序的第二个依据

vector<pair< int, int>> nums;

for( inti = 0; i < n; i++) {

nums.push_back({lst[i], i});

}

sort(nums.begin, nums.end);

// 初始化一个长度为 3 的数组,用于储存三个数的下标,初始化均为 n

vector< int> ansIdx( 3, n) ;

// 考虑第一个数 first

for( inti = 0; i < n - 2; i++) {

// 如果发现第 i、第 i+1、第 i+2 个数的和加起来超过 target

// 则更靠后的选择肯定和更大,直接退出循环

if(nums[i].first + nums[i + 1].first + nums[i + 2].first > target) {

break;

}

// 去重操作,如果遇到连续两个数相等,那么考虑 nums[i] 和考虑 nums[i-1] 所作的计算是一样的

// 直接跳过 nums[i] 的计算

if(i != 0&& nums[i].first == nums[i - 1].first) {

continue;

}

// 构建相向双指针 left 和 right

intleft = i + 1, right = n - 1;

while(left < right) {

// 计算三个数的和

intsum3 = nums[i].first + nums[left].first + nums[right].first;

// 三数和太大,right 左移

if(sum3 > target) {

right--;

}

// 三数和太小,left 右移

elseif(sum3 < target) {

left++;

}

// 三数和等于 target,如果三个下标和比之前记录过的三数下标和更小

// 则更新 ansIdx

else{

if(accumulate(ansIdx.begin, ansIdx.end, 0) > nums[i].second + nums[left].second + nums[right].second) {

ansIdx = {nums[i].second, nums[left].second, nums[right].second};

}

// 注意此处,只需要写 righ-- 就行,不需要加上 left++

// 1. 只写right -= 1就可以保证代码不会陷入死循环

// 因为只需要保证每一个if分支中,至少有一个指针是在变化的(也就是我们选择的right)

// 那么while中的left < right条件就一定会有不成立的时候

// 2. 由于排序时先按照num大小排列,再按照num在原数组中的索引排列。

// 如果此时存在 nums[right-1][0] == nums[right][0]

// 那么nums[right-1][1]会小于nums[right][1]

// i, nums[left][1]和nums[right-1][1]可以构成更小的索引和

// 如果加上了 left++ ,可能会漏算全局最小的索引和

right--;

}

}

}

// 退出循环,ansIdx 为在原数组中的三个数的下标

// 答案需要按照下标大小进行排列

sort(ansIdx.begin, ansIdx.end);

for( inti = 0; i < 3; i++) {

cout<< lst[ansIdx[i]];

if(i < 2) {

cout<< ",";

}

}

cout<< endl;

return0;

}

C# include<stdio.h>

# include<stdlib.h>

# include<limits.h>

# include<string.h>

// 定义结构体用于存储数值和下标

typedefstruct{

intvalue;

intindex;

} Pair;

// 比较函数,用于排序

intcompare( constvoid*a, constvoid*b) {

Pair *p1 = (Pair *)a;

Pair *p2 = (Pair *)b;

if(p1->value != p2->value) {

returnp1->value - p2->value;

}

returnp1->index - p2->index;

}

intmain{

// 输入原数组

charinput[ 10000];

if(!fgets(input, sizeof(input), stdin)) {

fprintf( stderr, "Error reading input\n");

return1;

}

intlst[ 1000], n = 0, target;

char*token = strtok(input, ",");

while(token != NULL) {

if(n >= 1000) {

fprintf( stderr, "Input exceeds maximum array size\n");

return1;

}

lst[n++] = atoi(token);

token = strtok( NULL, ",");

}

// 输入目标和

if( scanf( "%d", &target) != 1) {

fprintf( stderr, "Error reading target\n");

return1;

}

// 检查是否有足够的元素

if(n < 3) {

fprintf( stderr, "Not enough elements in input\n");

return1;

}

// 构建一个Pair数组用于存储数值和下标

Pair nums[ 1000];

for( inti = 0; i < n; i++) {

nums[i].value = lst[i];

nums[i].index = i;

}

// 对nums数组按值和下标排序

qsort(nums, n, sizeof(Pair), compare);

// 初始化用于存储答案的下标数组

intans_idx[ 3] = {INT_MAX, INT_MAX, INT_MAX};

// 遍历第一个数

for( inti = 0; i < n - 2; i++) {

// 如果三数之和超过目标和,退出循环

if(nums[i].value + nums[i + 1].value + nums[i + 2].value > target) {

break;

}

// 去重操作

if(i > 0&& nums[i].value == nums[i - 1].value) {

continue;

}

// 双指针初始化

intleft = i + 1, right = n - 1;

while(left < right) {

intsum3 = nums[i].value + nums[left].value + nums[right].value;

if(sum3 > target) {

right--;

} elseif(sum3 < target) {

left++;

} else{

// 如果当前索引和更小,则更新答案

if(nums[i].index + nums[left].index + nums[right].index <

ans_idx[ 0] + ans_idx[ 1] + ans_idx[ 2]) {

ans_idx[ 0] = nums[i].index;

ans_idx[ 1] = nums[left].index;

ans_idx[ 2] = nums[right].index;

}

// 注意此处,只需要写 righ-- 就行,不需要加上 left++

// 1. 只写right -= 1就可以保证代码不会陷入死循环

// 因为只需要保证每一个if分支中,至少有一个指针是在变化的(也就是我们选择的right)

// 那么while中的left < right条件就一定会有不成立的时候

// 2. 由于排序时先按照num大小排列,再按照num在原数组中的索引排列。

// 如果此时存在 nums[right-1][0] == nums[right][0]

// 那么nums[right-1][1]会小于nums[right][1]

// i, nums[left][1]和nums[right-1][1]可以构成更小的索引和

// 如果加上了 left++ ,可能会漏算全局最小的索引和

right--;

}

}

}

// 如果没有找到答案,直接退出

if(ans_idx[ 0] == INT_MAX) {

return1;

}

// 按下标大小排序

for( inti = 0; i < 2; i++) {

for( intj = 0; j < 2- i; j++) {

if(ans_idx[j] > ans_idx[j + 1]) {

inttemp = ans_idx[j];

ans_idx[j] = ans_idx[j + 1];

ans_idx[j + 1] = temp;

}

}

}

// 输出答案

printf( "%d,%d,%d\n", lst[ans_idx[ 0]], lst[ans_idx[ 1]], lst[ans_idx[ 2]]);

return0;

}

Node Java// 导入必要的模块

constreadline = require( "readline");

// 创建输入接口

constrl = readline.createInterface({

input: process.stdin,

output: process.stdout,

});

rl.question( "", (line1) => {

rl.question( "", (line2) => {

constlst = line1.split( ",").map( Number); // 读取并解析输入数组

consttarget = parseInt(line2); // 读取目标和

constn = lst.length; // 获取数组长度

// 对原数组进行排序,同时记录下标

constnums = lst

.map( ( num, i) => ({ num, index: i }))

.sort( ( a, b) => a.num - b.num || a.index - b.index);

// 初始化用于存储三个数下标的数组,初始值为正无穷

letansIdx = [ Infinity, Infinity, Infinity];

// 遍历第一个数

for( leti = 0; i < n - 2; i++) {

constfirst = nums[i].num;

constidx = nums[i].index;

// 如果当前三个数的最小和已经超过目标值,直接退出循环

if(nums[i].num + nums[i + 1].num + nums[i + 2].num > target) {

break;

}

// 去重操作,跳过连续相同的数字

if(i > 0&& nums[i].num === nums[i - 1].num) {

continue;

}

// 双指针初始化

letleft = i + 1,

right = n - 1;

while(left < right) {

constsum3 = first + nums[left].num + nums[right].num;

if(sum3 > target) {

right--;

} elseif(sum3 < target) {

left++;

} else{

// 如果当前索引和更小,更新答案

constcandidateIdx = [idx, nums[left].index, nums[right].index];

constcandidateSum = candidateIdx.reduce( ( a, b) => a + b, 0);

constcurrentSum = ansIdx.reduce( ( a, b) => a + b, 0);

if(candidateSum < currentSum) {

ansIdx = candidateIdx;

}

// 注意此处,只需要写 righ-- 就行,不需要加上 left++

// 1. 只写right -= 1就可以保证代码不会陷入死循环

// 因为只需要保证每一个if分支中,至少有一个指针是在变化的(也就是我们选择的right)

// 那么while中的left < right条件就一定会有不成立的时候

// 2. 由于排序时先按照num大小排列,再按照num在原数组中的索引排列。

// 如果此时存在 nums[right-1][0] == nums[right][0]

// 那么nums[right-1][1]会小于nums[right][1]

// i, nums[left][1]和nums[right-1][1]可以构成更小的索引和

// 如果加上了 left++ ,可能会漏算全局最小的索引和

right--;

}

}

}

// 按照下标排序

ansIdx.sort( ( a, b) => a - b);

// 输出结果

console.log(ansIdx.map( ( idx) => lst[idx]).join( ","));

rl.close;

});

});

Gopackagemain

import(

"bufio"

"fmt"

"os"

"sort"

"strconv"

"strings"

)

typePair struct{

Num int

Index int

}

funcmain{

reader := bufio.NewReader(os.Stdin)

line1, _ := reader.ReadString( '\n')

line1 = strings.TrimSpace(line1)

line2, _ := reader.ReadString( '\n')

line2 = strings.TrimSpace(line2)

// 解析输入

strNums := strings.Split(line1, ",")

lst := make([] int, len(strNums))

fori, s := rangestrNums {

lst[i], _ = strconv.Atoi(s)

}

target, _ := strconv.Atoi(line2)

n := len(lst)

// 对原数组进行排序,同时记录下标

nums := make([]Pair, n)

fori := 0; i < n; i++ {

nums[i] = Pair{Num: lst[i], Index: i}

}

sort.Slice(nums, func(i, j int) bool{

ifnums[i].Num == nums[j].Num {

returnnums[i].Index < nums[j].Index

}

returnnums[i].Num < nums[j].Num

})

// 初始化用于存储三个数下标的数组,初始值为正无穷

ansIdx := [] int{ 1<< 30, 1<< 30, 1<< 30}

// 遍历第一个数

fori := 0; i < n -2; i++ {

first := nums[i].Num

idx := nums[i].Index

// 如果当前三个数的最小和已经超过目标值,直接退出循环

ifnums[i].Num+nums[i+ 1].Num+nums[i+ 2].Num > target {

break

}

// 去重操作,跳过连续相同的数字

ifi > 0&& nums[i].Num == nums[i -1].Num {

continue

}

// 双指针初始化

left, right := i+ 1, n -1

forleft < right {

sum3 := first + nums[left].Num + nums[right].Num

ifsum3 > target {

right--

} elseifsum3 < target {

left++

} else{

// 如果当前索引和更小,更新答案

candidateIdx := [] int{idx, nums[left].Index, nums[right].Index}

candidateSum := candidateIdx[ 0] + candidateIdx[ 1] + candidateIdx[ 2]

currentSum := ansIdx[ 0] + ansIdx[ 1] + ansIdx[ 2]

ifcandidateSum < currentSum {

ansIdx = candidateIdx

}

// 注意此处,只需要写 righ-- 就行,不需要加上 left++

// 1. 只写right -= 1就可以保证代码不会陷入死循环

// 因为只需要保证每一个if分支中,至少有一个指针是在变化的(也就是我们选择的right)

// 那么while中的left < right条件就一定会有不成立的时候

// 2. 由于排序时先按照num大小排列,再按照num在原数组中的索引排列。

// 如果此时存在 nums[right-1][0] == nums[right][0]

// 那么nums[right-1][1]会小于nums[right][1]

// i, nums[left][1]和nums[right-1][1]可以构成更小的索引和

// 如果加上了 left++ ,可能会漏算全局最小的索引和

right--

}

}

}

// 按照下标排序

sort.Ints(ansIdx)

// 输出结果

fmt.Printf( "%d,%d,%d\n", lst[ansIdx[ 0]], lst[ansIdx[ 1]], lst[ansIdx[ 2]])

}

时空复杂度

时间复杂度:O(``n^2+nlogn``)。O(n^2)为双重循环所需时间复杂度,O(nlogn)为排序所需的时间复杂度。

空间复杂度:O(``n``)。列表nums所占空间。

Copyright © 转乾企业管理-加盟网 版权所有 | 黔ICP备2023009682号-14

免责声明:本站内容仅用于学习参考,信息和图片素材来源于互联网,如内容侵权与违规,请联系我们进行删除,我们将在三个工作日内处理。联系邮箱:303555158#QQ.COM (把#换成@)