腾讯今年的校招薪资。。。。

探讨腾讯2024年校园招聘的程序员薪酬策略,包括不同级别Offer,以及链表翻转问题的解法,涉及递归和虚拟节点技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 2024 年,腾讯的校园招聘再次证明了其作为中国互联网行业巨头的地位

以下是对腾讯在2024年校园招聘期间针对程序员职位的薪酬待遇的详细分析(数据来源于网络):

  1. 普通Offer:普通Offer的薪酬范围为月薪19k-22k,年度总计薪酬在35w至43w之间。这个数字是基于月薪乘以16(考虑年终奖),再加上每月4k的房补和3w的签字费(仅部分岗位提供)计算得出。

  2. SP Offer:对于更高级的职位,即SP Offer,月薪在23k-24k之间,年薪在44w至49w之间。这个数字包括月薪乘以16,每月4k的房补,3w的签字费,以及6w/2年的股票。

  3. SSP Offer:SSP Offer提供最高的薪酬,月薪在26k-29k,年薪在50w至61w之间。这包括月薪乘以16,每月4k房补,5w签字费和6w-10w/2年的股票。

  4. 腾讯技术大咖计划:此外,腾讯还推出了针对卓越博士生的“腾讯技术大咖”招聘计划。此计划的总包Offer可达100w+,展示了腾讯对顶尖技术人才的高度重视。

科普之后,继续学习吧,腾讯的高频题奉上一道。

图片

题目描述如下:

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

这个问题要求我们将链表中的每k个节点作为一组进行翻转,如果链表中的节点数不是k的整数倍,那么最后剩余的节点保持原有顺序。思路如下:

  1. 设置虚拟节点:

    • 首先,我们创建一个虚拟节点 dummy,并将其 next 指向链表的头节点 head。这个虚拟节点是为了方便处理边界情况,如翻转链表的首部。

  2. 初始化指针:

    • pre 指针指向虚拟节点,它将用于标记每k个节点组的开始之前的节点。

    • end 指针也初始化为虚拟节点,它将用于遍历找到每k个节点组的末尾。

  3. 寻找并翻转k个节点组:

    • 使用一个 while 循环来遍历链表。在循环内部,我们首先使用一个 for 循环来定位当前k个节点组的末尾 (end 指针)。

    • 如果 end 为 null,意味着当前组的节点数少于k,我们就保持这部分链表不变,退出循环。

  4. 断开并翻转当前节点组:

    • 一旦找到k个节点组,我们将该组从链表中断开。next 指针保存了当前组之后部分的链表头。

    • 调用 reverse 函数来翻转这k个节点组。start 指针指向该组的头节点。

  5. 重新连接翻转后的链表:

    • 翻转后,我们重新连接链表。pre.next 指向翻转后的头节点(原来的 end),而翻转后的尾节点(原来的 start)连接到 next

  6. 更新指针,准备下一次迭代:

    • 更新 pre 和 end 指针,准备下一组k个节点的翻转。

  7. 返回结果:

    • 最终返回 dummy.next,这是翻转后的链表的头节点。

  8. 反转链表函数 reverse:

    • 这是一个递归函数,用于翻转链表的一部分。它递归地翻转直到到达链表尾部,然后逐层返回并更新每个节点的 next 指针,以实现翻转。

通过这种方法,我们可以有效地每k个节点为一组进行翻转,同时保持链表的其余部分不变。

这个问题的关键是对链表的操作技巧,包括使用虚拟节点处理边界情况,以及递归翻转链表的一部分。

递归函数的理解和链表的指针操作是这个问题的难点,但一旦掌握,便能有效解决类似的链表操作问题。

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        // 一开始设置一个虚拟节点,它的值为 -1,它的值可以设置为任何的数,因为我们根本不需要使用它的值
        ListNode dummy = new ListNode(-1);

        // 虚拟头节点的下一节点指向 head 节点
        // 如果原链表是  1 -->  2 -->  3
        // 那么加上虚拟头节点就是  -1 -->  1 -->  2 -->  3
        dummy.next = head;
      

        // 设置一个指针,指向此时的虚拟节点,pre 表示每次要翻转的链表的头结点的【上一个节点】
        // pre: -1 -->  1 -->  2 -->  3
        ListNode pre = dummy;

        // 设置一个指针,指向此时的虚拟节点,end 表示每次要翻转的链表的尾节点
        // end: -1 -->  1 -->  2 -->  3
        ListNode end = dummy;
        
        // 通过 while 循环,不断的找到翻转链表的尾部
        while( end.next  != null ){

            // 通过 for 循环,找到【每一组翻转链表的尾部】
            // 由于原链表按照 k 个一组进行划分会可能出现有一组的长度不足 k 个
            // 比如原链表 1 -->  2 -->  3 -->  4 -->  5
            // k = 2,划分了三组 1 -->  2, 3 -->  4, 5
            // 所以得确保 end 不为空才去找它的 next 指针,否则 null.next 会报错
            for(int i  = 0 ; i < k && end != null ; i++){
                // end 不断的向后移动,移动 k 次到达【每一组翻转链表的尾部】
                end = end.next;
            }

            // 如果发现 end == null,说明此时翻转的链表的节点数小于 k ,保存原有顺序就行
            if(end == null){
                // 直接跳出循环,只执行下面的翻转操作
                break;
            }

            
            // next 表示【待翻转链表区域】里面的第一个节点
            ListNode next = end.next;

            // 【翻转链表区域】的最尾部节点先断开
            end.next = null;


            // start 表示【翻转链表区域】里面的第一个节点
            ListNode start = pre.next;

            // 【翻转链表区域】的最头部节点和前面断开
            pre.next = null;

            // 这个时候,【翻转链表区域】的头节点是 start,尾节点是 end
            // 开始执行【反转链表】操作
            // 原先是 start --> ...--> end
            // 现在变成了 end --> ...--> start
            


            // 要翻转的链表的头结点的【上一个节点】的 next 指针指向这次翻转的结果
            pre.next = reverse(start);

            // 接下来的操作是在为【待翻转链表区域】的反转做准备

            // 原先是 start --> ...--> end
            // 现在变成了 end --> ...--> start
            // 【翻转链表区域】里面的尾节点的 next 指针指向【待翻转链表区域】里面的第一个节点
            start.next = next;
            // 原先是 start --> ...--> end
            // 现在变成了 end --> ...--> start
            // pre 表示每次要翻转的链表的头结点的【上一个节点】
            pre = start;

            // 将 end 重置为【待翻转链表区域】的头结点的上一个节点。
            end = start;
        }
        
        return dummy.next;

    }
  
    // 反转链表的代码
    private ListNode reverse(ListNode head) {
        // 寻找递归终止条件
        // 1、head 指向的结点为 null 
        // 2、head 指向的结点的下一个结点为 null 
        // 在这两种情况下,反转之后的结果还是它自己本身
        if( head == null || head.next == null)  return head;

        // 不断的通过递归调用,直到无法递归下去,递归的最小粒度是在最后一个节点
        // 因为到最后一个节点的时候,由于当前节点 head 的 next 节点是空,所以会直接返回 head
        ListNode cur = reverse(head.next);

        // 比如原链表为 1 --> 2 --> 3 --> 4 --> 5
        // 第一次执行下面代码的时候,head 为 4,那么 head.next = 5
        // 那么 head.next.next 就是 5.next ,意思就是去设置 5 的下一个节点
        // 等号右侧为 head,意思就是设置 5 的下一个节点是 4
        
        // 这里出现了两个 next
        // 第一个 next 是「获取」 head 的下一节点
        // 第二个 next 是「设置」 当前节点的下一节点为等号右侧的值
        head.next.next = head;

        // head 原来的下一节点指向自己,所以 head 自己本身就不能再指向原来的下一节点了
        // 否则会发生无限循环
        head.next = null;

        // 我们把每次反转后的结果传递给上一层
        return cur;

    }
}

 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值