学习笔记 | Leetcode 181周赛

学习笔记 | Leetcode 181周赛_第1张图片第一次参加周赛,只会答出来最简单的一题,第二题超时,第三、四题不会做,这里来总结一下,并希望下次有进步。
第181场leetcode 周赛

5364. 按既定顺序创建目标数组

给你两个整数数组 nums 和 index。你需要按照以下规则创建目标数组:

  • 目标数组 target 最初为空。
  • 按从左到右的顺序依次读取 nums[i] 和 index[i],在 target 数组中的下标 index[i] 处插入值 nums[i] 。
  • 重复上一步,直到在 nums 和 index 中都没有要读取的元素。

请你返回目标数组。

思路:题目比较简单,直接暴力求解即可

    vector<int> createTargetArray(vector<int>& nums, vector<int>& index) {
        vector<int> target(0);
        for(int i=0;i<nums.size();i++){
            target.insert(target.begin()+index[i],nums[i]);
        }
        return target;
    }

5178. 四因数

给你一个整数数组 nums,请你返回该数组中恰有四个因数的这些整数的各因数之和。

如果数组中不存在满足题意的整数,则返回 0 。

示例:

输入:nums = [21,4,7]
输出:32
解释: 21 有 4 个因数:1, 3, 7, 21
4 有 3 个因数:1, 2, 4
7 有 2 个因数:1, 7
答案仅为 21 的所有因数的和。

提示:
1 <= nums.length <= 10^4
1 <= nums[i] <= 10^5

未通过的思路:
第一反应就是暴力求解啊,隐约觉得可能超时,果不其然超时了,而且我考虑的也不周全,没有考虑到立方根的问题
学习笔记 | Leetcode 181周赛_第2张图片

看过大佬们的思路:4个因子的话,可以分为1和本身+剩下两个因子,这两个因子可以是质数相乘,但是如果是个立方根的话,就得舍去了。

#include 

class Solution {
public:
    int sumFourDivisors(vector<int>& nums) {
        int res = 0;
        
        for(int i = 0; i < nums.size(); ++i){
            int cnt = 0;
            int sum = 0;
            int sq = sqrt(nums[i]);

            for(int j = 2; j <= sq; ++j){
                if(nums[i] % j == 0){
                    cnt++;
                    sum += j;
                    sum += nums[i] / j;
                    
                }
                if(cnt > 1) break;
            }
            if(cnt == 1 && sq * sq != nums[i]){
                res = res + sum + nums[i] + 1;
            } 
        }
        
        return res;
    }
};



1391. 检查网格中是否存在有效路径
给你一个 m x n 的网格 grid。网格里的每个单元都代表一条街道。grid[i][j] 的街道可以是:

1 表示连接左单元格和右单元格的街道。
2 表示连接上单元格和下单元格的街道。
3 表示连接左单元格和下单元格的街道。
4 表示连接右单元格和下单元格的街道。
5 表示连接左单元格和上单元格的街道。
6 表示连接右单元格和上单元格的街道。

你最开始从左上角的单元格 (0,0) 开始出发,网格中的「有效路径」是指从左上方的单元格 (0,0) 开始、一直到右下方的 (m-1,n-1) 结束的路径。该路径必须只沿着街道走。

注意:你不能变更街道。

如果网格中存在有效的路径,则返回 true,否则返回 false 。

思路:这题其实袭击想的时候直到只要转换好就可以,但是无奈题刷得少,不知道咋转换,于是看了别的大佬的题解:链接

pipe[3][2]=3,代表3号拼图可以由向上的方向进入其中,并转向左方向继续前进。
pipe[5][3]=-1,代表5号拼图不可以由向左的方向进入其中。

class Solution {
    int m,n,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};//0下、1右、2上、3左
    int pipe[7][4]={
        {-1,-1,-1,-1},
        {-1,1,-1,3},
        {0,-1,2,-1},
        {-1,0,3,-1},
        {-1,-1,1,0},
        {3,2,-1,-1},
        {1,-1,-1,2}
    };
    //记录各个拼图块路径的方向,0、1、2、3代表方向,-1代表不可走。
    bool vis[302][302];
    bool dfs(int x,int y,int dir,vector<vector<int>>& grid){//(x,y,当前方向,地图)
        vis[x][y]=1;
        if(x==m-1&&y==n-1) return 1;//到达终点
        int xx=x+dx[dir];
        int yy=y+dy[dir];//得到下一个准备走的坐标
        if(xx<0||yy<0||xx>=m||yy>=n)return 0;//越界
        int nxt=grid[xx][yy];//得到下一块拼图的编号
        if(pipe[nxt][dir]!=-1&&!vis[xx][yy])
            return dfs(xx,yy,pipe[nxt][dir],grid);//如果当前方向可走,则方向改变,继续走。
        return 0;//无法走,返回0
    }
    public:
    bool hasValidPath(vector<vector<int>>& grid) {    
        m=grid.size();
        n=grid[0].size();
        memset(vis,0,sizeof(vis));
        int sta=grid[0][0];//起点的拼图编号
        for(int i=0;i<4;++i)//朝着四个方向都试一下
            if(pipe[sta][i]!=-1)//当前方向可以走
                if(dfs(0,0,pipe[sta][i],grid))//沿着当前方向搜索
                    return 1;//拼图都有两个方向可以走,只要沿着一个初始方向走通就可以。
        return 0;
    }
};

1392. 最长快乐前缀*
(这题还不是太懂,等我把简单+中等难度题刷的差不多了再回过头来看可能那时候就懂了。)

「快乐前缀」是在原字符串中既是 非空 前缀也是后缀(不包括原字符串自身)的字符串。 给你一个字符串 s,请你返回它的 最长快乐前缀。
如果不存在满足题意的前缀,则返回一个空字符串。

方法一:KMP算法

class Solution {
public:
    string longestPrefix(string s) {
        int n = s.size();
        vector<int> fail(n, -1);
        for (int i = 1; i < n; ++i) {
            int j = fail[i - 1];
            while (j != -1 && s[j + 1] != s[i]) {
                j = fail[j];
            }
            if (s[j + 1] == s[i]) {
                fail[i] = j + 1;
            }
        }
        return s.substr(0, fail[n - 1] + 1);
    }
};

来源:官方题解二

方法二:字符串Hash

typedef unsigned long long ULL;
class Solution {
public:
    string longestPrefix(string s) {
        int base = 131;
        ULL p[100002]; 
        p[0] = 1;
        ULL hash[100002]; 
        hash[0] = 0;
        for (int i = 1; i <= s.size(); i ++) {
            hash[i] = hash[i-1] * base + s[i-1] - 'a' + 1;
            p[i] = p[i-1] * base;
        }
        for (int i = s.size() - 1; i >= 1; i --) {
            ULL pre = hash[i];
            ULL suf = hash[s.size()] - hash[s.size()-i] * p[i];
            if (pre == suf) {
                return s.substr(0, i);
            }
        }
        return "";
    }
};

来源:huwt


总结与反思
这周考的算法主要是DFS和KMP算法,我主要是STL库运用还不够熟练。
毕竟才刷了几十道简单的题,不可能一下子进步很多,不过肉眼可见的确在进步中。
希望自己改进的点就是,要坚持每题都做总结,慢慢来,比较快。

你可能感兴趣的:(算法比赛)