leetcode第181场周赛题解

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

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

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

题目保证数字插入位置总是存在。

 

示例 1:

输入:nums = [0,1,2,3,4], index = [0,1,2,2,1]
输出:[0,4,1,3,2]
解释:
nums       index     target
0            0        [0]
1            1        [0,1]
2            2        [0,1,2]
3            2        [0,1,3,2]
4            1        [0,4,1,3,2]
示例 2:

输入:nums = [1,2,3,4,0], index = [0,1,2,3,0]
输出:[0,1,2,3,4]
解释:
nums       index     target
1            0        [1]
2            1        [1,2]
3            2        [1,2,3]
4            3        [1,2,3,4]
0            0        [0,1,2,3,4]
示例 3:

输入:nums = [1], index = [0]
输出:[1]
 

提示:

1 <= nums.length, index.length <= 100
nums.length == index.length
0 <= nums[i] <= 100
0 <= index[i] <= i

第一题,送分题,如果想给自己增加难度的话,可以自己写一个数据结构实现。

 

class Solution {
    public int[] createTargetArray(int[] nums, int[] index) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        for(int i=0;i<nums.length;i++)
        {
            result.add(index[i],nums[i]);
        }

        int[] res = new int[result.size()];
        for(int i=0;i<result.size();i++)
        {
            res[i] = result.get(i);
        }
        return res;
    }
}

1390. 四因数

给你一个整数数组 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

同样是送分题,就是注意一点,循环范围要取根号n,因为后面的部分就是重复计算了。如果不取,会超时。

class Solution {
    public int sumFourDivisors(int[] nums) {
        int res = 0;
        for(int i=0;i<nums.length;i++)
        {
            ArrayList<Integer> tmp = judge(nums[i]);
            if(tmp.get(0)==1)
            {
                for(int j=1;j<tmp.size();j++)
                {
                    res = res + tmp.get(j);
                }
            }
        }
        return res;
    }

    public ArrayList judge(int num){
        ArrayList<Integer> res = new ArrayList<Integer>();
        if(num==1)
        {
            res.add(0);
            return res;
        }
        for(int i=1;i<=Math.sqrt(num);i++)
        {
            if(num%i==0)
            {
                res.add(i);
                if(i!=num/i)
                    res.add(num/i);
                if(res.size()>4)
                    break;
            }
        }
        if(res.size()==4)
        {
            res.add(0,1);
        }
        else
        {
            res.add(0,0);
        }
        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 。

 

示例 1:

输入:grid = [[2,4,3],[6,5,2]]
输出:true
解释:如图所示,你可以从 (0, 0) 开始,访问网格中的所有单元格并到达 (m - 1, n - 1) 。
示例 2:

输入:grid = [[1,2,1],[1,2,1]]
输出:false
解释:如图所示,单元格 (0, 0) 上的街道没有与任何其他单元格上的街道相连,你只会停在 (0, 0) 处。
示例 3:

输入:grid = [[1,1,2]]
输出:false
解释:你会停在 (0, 1),而且无法到达 (0, 2) 。
示例 4:

输入:grid = [[1,1,1,1,1,1,3]]
输出:true
示例 5:

输入:grid = [[2],[2],[2],[2],[2],[2],[6]]
输出:true
 

提示:

m == grid.length
n == grid[i].length
1 <= m, n <= 300
1 <= grid[i][j] <= 6

这个题证明我的编程水平是真的下降了,往常应该能马上想到并查集的,确实太典型了。现在我遇见这个题的第一反应是深度优先搜索,其实很容易看到,这个题目中,如果有路径,那么路径只此一条。因此从起点开始,只要有路,我们就走,能走到重点就是true,反之则是false。看上去蛮简单的,但是一个极大的问题就是,实在是太麻烦了!每种地图的对应编码写的我头疼,所以这个题还是最好用并查集,与前文思路不同的地方是,我们不需要分析地图点和点间是怎样联通的,只需要计算两个点间是不是联通的就可以了。

代码来自leetcode题解。

class Solution {
public:
static constexpr int MAX_N = 300 * 300 + 5;
    int n = -1;
    int m = -1;
    vector<vector<int>> g;
    struct DisjointSet {
        int f[MAX_N];
        
        DisjointSet() {
            for (int i = 0; i < MAX_N; ++i) f[i] = i;
        }
        
        int find(int x) {
            return x == f[x] ? x : f[x] = find(f[x]);
        }
        
        void merge(int x, int y) {
            f[find(x)] = find(y);
        }
    } ds;

    int getId (int x, int y)
    {
        return x * m + y;
    }
    void detectL(int x, int y)
    {
        if (y - 1 >= 0 && (g[x][y - 1] == 4 || g[x][y - 1] == 6 || g[x][y - 1] == 1)) 
        {
            ds.merge(getId(x, y), getId(x, y - 1));
        }
    } 

    void detectR(int x, int y)
    {
        if (y + 1 < m && (g[x][y + 1] == 3 || g[x][y + 1] == 5 || g[x][y + 1] == 1)) 
        {
            ds.merge(getId(x, y), getId(x, y + 1));
        }
    }

    void detectU(int x, int y)
    {
        if (x - 1 >= 0 && (g[x - 1][y] == 3 || g[x - 1][y] == 4 || g[x - 1][y] == 2)) 
        {
            ds.merge(getId(x, y), getId(x - 1, y));
        }
    }

    void detectD(int x, int y)
    {
        if (x + 1 < n && (g[x + 1][y] == 5 || g[x + 1][y] == 6 || g[x + 1][y] == 2)) 
        {
            ds.merge(getId(x, y), getId(x + 1, y));
        }
    }

    void handle(int x, int y) 
    {
        switch (g[x][y]) {
            case 1: {
                detectL(x, y); detectR(x, y);
            } break;
            case 2: {
                detectU(x, y); detectD(x, y);
            } break;
            case 3: {
                detectL(x, y); detectD(x, y);
            } break;
            case 4: {
                detectR(x, y); detectD(x, y);
            } break;
            case 5: {
                detectL(x, y); detectU(x, y);
            } break;
            case 6: {
                detectR(x, y); detectU(x, y);
            }
        }
    }



    bool hasValidPath(vector<vector<int>>& grid) {
        g = grid;
        n = grid.size();
        m = grid[0].size();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                handle(i, j);
            }
        }

        return ds.find(getId(0, 0)) == ds.find(getId(n - 1, m - 1));
    };
};

1392. 最长快乐前缀

「快乐前缀」是在原字符串中既是 非空 前缀也是后缀(不包括原字符串自身)的字符串。

给你一个字符串 s,请你返回它的 最长快乐前缀。

如果不存在满足题意的前缀,则返回一个空字符串。

 

示例 1:

输入:s = "level"
输出:"l"
解释:不包括 s 自己,一共有 4 个前缀("l", "le", "lev", "leve")和 4 个后缀("l", "el", "vel", "evel")。最长的既是前缀也是后缀的字符串是 "l" 。
示例 2:

输入:s = "ababab"
输出:"abab"
解释:"abab" 是最长的既是前缀也是后缀的字符串。题目允许前后缀在原字符串中重叠。
示例 3:

输入:s = "leetcodeleet"
输出:"leet"
示例 4:

输入:s = "a"
输出:""
 

提示:

1 <= s.length <= 10^5
s 只含有小写英文字母

KMP算法的应用,答案来自leetcode题解。

class Solution {
  public String longestPrefix(String s) {
    int[] next = getNext(s);
    int n = next[s.length()];
    return s.substring(0, n);
  }

  int[] getNext(String s) {
    int[] next = new int[s.length() + 1];
    int i = 0, j = -1;
    next[0] = -1;
    while (i < s.length()) {
      if (j == -1 || s.charAt(j) == s.charAt(i))
        // 已有 [0, ..., j - 1] 与 [i - j, ..., i - 1] 匹配, 同时 s[j] == s[i]
        next[++i] = ++j;
        // 匹配长度增加 1, 查看下一个匹配位置
      else
        j = next[j];
        // 不匹配, 说明当前查看的前缀太长, 将 j 跳回到上一个可能的匹配位置
    }
    return next;
  }
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值