查看原文
其他

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

脚本之家 2024-01-16

The following article is from 吴师兄学算法 Author 吴师兄

将 脚本之家 设为“星标
第一时间收到文章更新
来源公众号:吴师兄学算法  ID:CXYxiaow

在 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。这个虚拟节点是为了方便处理边界情况,如翻转链表的首部。
  • 初始化指针:
    • pre 指针指向虚拟节点,它将用于标记每k个节点组的开始之前的节点。
    • end 指针也初始化为虚拟节点,它将用于遍历找到每k个节点组的末尾。
  • 寻找并翻转k个节点组:
    • 使用一个 while 循环来遍历链表。在循环内部,我们首先使用一个 for 循环来定位当前k个节点组的末尾 (end 指针)。
    • 如果 endnull,意味着当前组的节点数少于k,我们就保持这部分链表不变,退出循环。
  • 断开并翻转当前节点组:
    • 一旦找到k个节点组,我们将该组从链表中断开。next 指针保存了当前组之后部分的链表头。
    • 调用 reverse 函数来翻转这k个节点组。start 指针指向该组的头节点。
  • 重新连接翻转后的链表:
    • 翻转后,我们重新连接链表。pre.next 指向翻转后的头节点(原来的 end),而翻转后的尾节点(原来的 start)连接到 next
  • 更新指针,准备下一次迭代:
    • 更新 preend 指针,准备下一组k个节点的翻转。
  • 返回结果:
    • 最终返回 dummy.next,这是翻转后的链表的头节点。
  • 反转链表函数 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;

        }
    }

      推荐阅读:
    1. 大厂程序员提倡“防御性编程”:故意把代码写得很烂,万一自己被裁,要确保留下的代码不可维护!
    2. 雷军三十年前计算机论文曝光:“这种智能判定方法,国内外文献尚未提及”
    3. 有这个迹象,公司就要凉了
    4. 工作群,“逼疯”打工人
    5. 计算机科学考古:冯·诺依曼的第一个计算机程序
    继续滑动看下一个

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

    向上滑动看下一个

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存