第321场周赛赛后总结(前三题)+记录一道有意思的题目

简介: 前言 今天早上可能是浏览器出了点故障,一直没法打开力扣官网页面(但别的页面没问题)(别人都能进说明不是官网服务器的问题咯),错过了周赛(不过就算按时参加估计也是陪跑,就先这么安慰自己了),下午发现能进去了,赶紧找个时间补了一下题。
本文首发于稀土掘金。该平台的作者 逐光而行 也是本人。

前言

今天早上可能是浏览器出了点故障,一直没法打开力扣官网页面(但别的页面没问题)(别人都能进说明不是官网服务器的问题咯),错过了周赛(不过就算按时参加估计也是陪跑,就先这么安慰自己了),下午发现能进去了,赶紧找个时间补了一下题。

题目、代码、思路

找出中枢整数

给你一个正整数 n ,找出满足下述条件的 中枢整数 x :

  • 1 和 x 之间的所有元素之和等于 x 和 n 之间所有元素之和。

返回中枢整数 **x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中枢整数。

思路:
这个可以利用数学公式:对连续自然数a1到an相加的和=(a1+an)*项数n/2

对题目进行变形可得:(1+x)x=(x+n)(n-x+1)

代码如下:

class Solution {
    public int pivotInteger(int n) {
        for(int x=1;x<=n;x++){
            if((1+x)*x==(x+n)*(n-x+1)) return x;
        }
        return -1;
    }
}

追加字符以获得子序列

给你两个仅由小写英文字母组成的字符串  s 和  t 。

现在需要通过向 s 末尾追加字符的方式使 t 变成 s 的一个 子序列 ,返回需要追加的最少字符数。

子序列是一个可以由其他字符串删除部分(或不删除)字符但不改变剩下字符顺序得到的字符串。

思路:这是一个很典型的双指针问题,指针i j同时开始遍历s和t,i走得快些,j走得慢些,最后j停住不动了,剩下它走不完的就是要在s末尾补上去的字符。

class Solution {
    public int appendCharacters(String s, String t) {
        int cnt=0;
        int n=s.length(),m=t.length();
        int i=0,j=0;
        while(i<n&&j<m){
            if(s.charAt(i)==t.charAt(j)){
                i++;
                j++;
            }
            else i++;
        }
        cnt=m-j;
        return cnt;
    }
}

从链表中移除结点

给你一个链表的头节点  head 。

对于列表中的每个节点 node ,如果其右侧存在一个具有 严格更大 值的节点,则移除 node 。

返回修改后链表的头节点 head

思路:这一题和传统的删除链表不一样的是:它移除的是当前的结点。

以往做的删除结点的常规思路都是:找到待删除结点的前一个结点,然后通过pre.next=pre.next.next的方式跳过当前结点。

这里题意变了,做法也相应变了。

可以采用递归的思路。注意三点:

  • 递归结束条件:

if(head==null) return null;

  • 如果选择不删除当前结点,也得把它的后续再接上一遍:
    head.next=nxt;
    因为有可能在前面递归时head后面的部分已经丢失了。

完整代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNodes(ListNode head) {
        if(head==null) return null;
        ListNode nxt=removeNodes(head.next);
        if(nxt!=null&&head.val<nxt.val){
            return nxt;
        }
        else{
            head.next=nxt;
            return head;
        }
    }
}
  • 一点题外话:昨天做到了另外一道变形题,不提供头结点,要求你删除当前给定的结点。

6247 删除链表中的结点

有一个单链表的 head,我们想删除它其中的一个节点 node

给你一个需要删除的节点 node 。你将 无法访问 第一个节点  head

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

  • 给定节点的值不应该存在于链表中。
  • 链表中的节点数应该减少 1。
  • node 前面的所有值顺序相同。
  • node 后面的所有值顺序相同。

这道题的思路很有意思:如果想要A从世界上消失,只需要让它顶替B的位置:

class Solution {
    public void deleteNode(ListNode node) {
        int val=node.next.val;
        node.val=val;
        node.next=node.next.next;
    }
}

个人感觉这两题值得放在一起对比一下,别搞混了。

最后补一道今天做的打卡题,难度hard,个人感觉挺有意思,也较有实际意义

1203 项目管理

有 n 个项目,每个项目或者不属于任何小组,或者属于 m 个小组之一。group[i] 表示第 i 个项目所属的小组,如果第 i 个项目不属于任何小组,则 group[i] 等于 -1。项目和小组都是从零开始编号的。可能存在小组不负责任何项目,即没有任何项目属于这个小组。

请你帮忙按要求安排这些项目的进度,并返回排序后的项目列表:

  • 同一小组的项目,排序后在列表中彼此相邻。
  • 项目之间存在一定的依赖关系,我们用一个列表 beforeItems 来表示,其中 beforeItems[i] 表示在进行第 i 个项目前(位于第 i 个项目左侧)应该完成的所有项目。

如果存在多个解决方案,只需要返回其中任意一个即可。如果没有合适的解决方案,就请返回一个 空列表

思路解析已经很详细地体现在代码注释中了,这里就不多赘述了。

class Solution {
    public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
        //数据预处理,给没有组号的编上新组号,免得后续全挤在一起
        for(int i=0;i<group.length;i++){
            if(group[i]==-1){
                group[i]=m;
                m++;
            }
        }

        //构建组和项目的邻接表
        List<Integer> [] itemList=new List [n];
        List<Integer> [] groupList=new List [m];
        for(int i=0;i<n;i++){
            itemList[i]=new ArrayList<>();
        }
        for(int i=0;i<m;i++){
            groupList[i]=new ArrayList<>();
        }

        //建图 统计入度
        int [] itemDegree=new int [n];
        int [] groupDegree=new int [m];

        for(int i=0;i<group.length;i++){
            int curgroup=group[i];
            for(int preitem:beforeItems.get(i)){
                int pregroup=group[preitem];
                if(curgroup!=pregroup){
                    groupList[pregroup].add(curgroup);
                    groupDegree[curgroup]++;
                }
            }
        }

        for(int i=0;i<n;i++){
            for(int pre:beforeItems.get(i)){
                itemList[pre].add(i);
                itemDegree[i]++;
            }
        }

        //得到拓扑排序结果
        List<Integer> tuopuitem=tuopuSort(itemList,itemDegree,n);
        List<Integer> tuopugroup=tuopuSort(groupList,groupDegree,m);
        if(tuopuitem.size()==0||tuopugroup.size()==0) return new int [0];

        //建立组到项目的一对多关系
        Map<Integer,List<Integer>> groupToitems=new HashMap<>();
        for(Integer item:tuopuitem){
            groupToitems.computeIfAbsent(group[item],key->new ArrayList<>()).add(item);
        }

        //组的拓扑结构->项目的拓扑结构
        List<Integer> res=new ArrayList<>();
        for(Integer id:tuopugroup){
            List<Integer> items=groupToitems.getOrDefault(id,new ArrayList<>());
            res.addAll(items);
        }
        int len=res.size();
        int [] ans=new int [len];
        for(int i=0;i<len;i++){
            ans[i]=res.get(i);
        }
        return ans;
    }

    public List<Integer> tuopuSort(List<Integer> [] list,int [] degree,int len){
        List<Integer> res=new ArrayList<>();
        //拓扑排序,使用队列做
        Queue<Integer> queue=new LinkedList<>();
        //将所有没有前驱结点的结点入队(入度为0)
        for(int i=0;i<len;i++){
            if(degree[i]==0) queue.offer(i);
        }

        /** 算法核心:
        将没有前驱节点的结点逐个出队并添加至结果中;
        逐个遍历这些节点的后继节点,并且标记已访问(取消它的度)
        当它没有入度时也将其归入没有前驱结点的阵列(入队)
        */
        while(!queue.isEmpty()){
            int top=queue.poll();
            res.add(top);
            for(int nxt:list[top]){
                degree[nxt]--;
                if(degree[nxt]==0){
                    queue.offer(nxt);
                }
            }
        }
        return res.size()==len?res:new ArrayList<>();
    }
}

以上就是本文的全部内容啦!喜欢的小伙伴们欢迎点个赞再走哦!

相关文章
|
9月前
|
算法 Android开发 Kotlin
LeetCode 周赛上分之旅 #42 当 LeetCode 考树上倍增,出题的趋势在变化吗
学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode 周赛的解题报告,一起体会上分之旅。
93 0
LeetCode 周赛上分之旅 #42 当 LeetCode 考树上倍增,出题的趋势在变化吗
|
9月前
|
C++ Python
【浙江大学PAT真题练习乙级】1001 害死人不偿命的(3n+1)猜想(15分)真题解析
【浙江大学PAT真题练习乙级】1001 害死人不偿命的(3n+1)猜想(15分)真题解析
|
10月前
|
算法 JavaScript Android开发
LeetCode 周赛上分之旅 #33 摩尔投票派上用场
学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode 周赛的解题报告,一起体会上分之旅。
56 0
|
12月前
|
人工智能 算法 C++
【每日算法Day 88】超越妹妹教你如何做这道排序题
【每日算法Day 88】超越妹妹教你如何做这道排序题
|
12月前
|
机器学习/深度学习
HZU蓝桥杯校内第二次选拔赛题解
HZU蓝桥杯校内第二次选拔赛题解
53 0
|
算法 测试技术
刷爆 LeetCode 双周赛 100,单方面宣布第一题最难
上周末是 LeetCode 第 100 场双周赛,你参加了吗?这场周赛整体没有 Hard 题,但是也没有 Easy 题。第一题国服前百名里超过一半人 wa,很少见。
96 0
|
Android开发
LeetCode 双周赛 98,脑筋急转弯转不过来!
大家好,我是小彭。 昨晚是 LeetCode 第 98 场双周赛,你参加了吗?这场周赛需要脑筋急转弯,转不过来 Medium 就会变成 Hard,转得过来就变成 Easy。
67 0
周赛313赛后做题分析及总结
本文为力扣周赛313赛后做题分析及总结。
72 0
|
测试技术
2021年第十二届蓝桥杯模拟赛(第四期)题目和解析
蓝桥杯是指蓝桥杯全国软件和信息技术专业人才大赛。是由工业和信息化部人才交流中心举办的全国性IT学科赛事。共有北京大学、清华大学、上海交通大学等全国1200余所高校参赛。
156 0
2021年第十二届蓝桥杯模拟赛(第四期)题目和解析
|
人工智能 测试技术
2021年第十二届蓝桥杯模拟赛(第三期)题目和解析
蓝桥杯是指蓝桥杯全国软件和信息技术专业人才大赛。是由工业和信息化部人才交流中心举办的全国性IT学科赛事。共有北京大学、清华大学、上海交通大学等全国1200余所高校参赛。
325 0
2021年第十二届蓝桥杯模拟赛(第三期)题目和解析