174届lectcode周赛总结

第一题

要求

给你一个大小为 m * n 的方阵 mat,方阵由若干军人和平民组成,分别用 0 和 1 表示。

请你返回方阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。

如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。

军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。

示例

示例 1:

输入:mat =
[[1,1,0,0,0],
[1,1,1,1,0],
[1,0,0,0,0],
[1,1,0,0,0],
[1,1,1,1,1]],
k = 3
输出:[2,0,3]
解释:
每行中的军人数目:
行 0 -> 2
行 1 -> 4
行 2 -> 1
行 3 -> 2
行 4 -> 5
从最弱到最强对这些行排序后得到 [2,0,3,1,4]
示例 2:

输入:mat =
[[1,0,0,0],
[1,1,1,1],
[1,0,0,0],
[1,0,0,0]],
k = 2
输出:[0,2]
解释:
每行中的军人数目:
行 0 -> 1
行 1 -> 4
行 2 -> 1
行 3 -> 1
从最弱到最强对这些行排序后得到 [0,2,3,1]

提示:

m == mat.length
n == mat[i].length
2 <= n, m <= 100
1 <= k <= m
matrix[i][j] 不是 0 就是 1

代码

  • 二分法

vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
    int m = mat.size();
    int n = mat[0].size();
    vector<pair<int,int>> res;
    vector<int> ret;
    for(int i = 0;i<m;i++)
    {
        int left = 0,right = n-1;
        while(left<right)
        {
            int mid = (left + right)/2;
            if(mat[i][mid]==1) left = mid + 1;
            else right = mid - 1;
        }
        if(mat[i][left]==0) left = left-1;
        res.push_back({left,i});
    }
    sort(res.begin(),res.end());
    for(int i =0;i<k;i++) ret.push_back(res[i].second);
    return ret;
}
  • 从前排查找(按列遍历)

vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
    int m = mat.size(),n = mat[0].size(),flag = 0;
    vector<int> res;
    for(int i = 0;i<n;i++)
    {
        for(int j = 0;j<m;j++)
        {
            if(mat[j][i]==0)
                if(find(res.begin(),res.end(),j)==res.end())
                    res.push_back(j);
            if(res.size()==k) return res;
        }
    }
    for(int i = 0; i < m; i++)
    {
        if(mat[i][n - 1] == 1) 
        {
            res.push_back(i);
        }
        if(k == res.size()) break;
    }
    return res;
}
  • 从前排查找相当于先按列遍历,第一个遇到0的肯定是士兵数最少的,注意已经满足要求的就不能在算了,要去重。还有一点是遍历完并没有取完,说明有全都是士兵的列,这时,从小序号往大序号直接添加之前没有取到的行。

第二题

要求

给你一个整数数组 arr。你可以从中选出一个整数集合,并删除这些整数在数组中的每次出现。

返回 至少 能删除数组中的一半整数的整数集合的最小大小。

示例

示例 1:

输入:arr = [3,3,3,3,5,5,5,2,2,7]
输出:2
解释:选择 {3,7} 使得结果数组为 [5,5,5,2,2]、长度为 5(原数组长度的一半)。
大小为 2 的可行集合有 {3,5},{3,2},{5,2}。
选择 {2,7} 是不可行的,它的结果数组为 [3,3,3,3,5,5,5],新数组长度大于原数组的二分之一。
示例 2:

输入:arr = [7,7,7,7,7,7]
输出:1
解释:我们只能选择集合 {7},结果数组为空。
示例 3:

输入:arr = [1,9]
输出:1

代码

int minSetSize(vector<int>& arr) {
   unordered_map<int,int> mp;
   for(int i = 0;i<arr.size();i++)
   mp[arr[i]]++;
   vector<int> temp;
   for(unordered_map<int,int>::iterator it=mp.begin();it!=mp.end();it++)
   temp.push_back(it->second);
   sort(temp.begin(),temp.end());
   int sum = 0,res = 0;
   for(int i = temp.size()-1;i>=0;i--)
   {
       sum += temp[i];
       res++;
       if(sum>=(arr.size()/2)) break;
   }
   return res;
}
  • 用哈希表储存每个元素储存的次数,因为题目要求至少删除一半,所以将每个元素出现次数按大小排序,从大往小的试,当满足大于容器一半大时,返回结果。

第三题

要求

给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。

由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回。

示例

输入:root = [1,2,3,4,5,6]
输出:110
解释:删除红色的边,得到 2 棵子树,和分别为 11 和 10 。它们的乘积是 110 (11*10)

代码

vector<long> ret;
int maxProduct(TreeNode* root) {
    long sum = getcount(root),res = INT_MIN;
    for(int i = 0;i<ret.size();i++)
    {
        long x = ret[i]*(sum - ret[i]);
        res = max(res,x);
    }
    return res%(1000000007);
}
int getcount(TreeNode *root) //用来求以每个节点为根节点其和。
{
    if(root==nullptr) return 0;
    int temp = root->val + getcount(root->left) + getcount(root->right);
    ret.push_back(temp);
    return temp;
}
  • 此题主要求了一个二叉树所有节点之和这个知识点,其他的较好理解。

第四题:跳跃游戏(点击此处)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值