力扣第331场周赛题解

rank T1 T2 T3 T4
331 / 4256 0:01:46 0:06:18 (1) 0:11:58 0:57:29 (4)

T1 从数量最多的堆取走礼物

模拟题,每次操作找出最大值

m

a

x

x

maxx

maxx并将其变成

s

q

r

t

(

m

a

x

x

)

sqrt(maxx)

sqrt(maxx)

k

k

k次操作后求和。

数据范围很小,可以暴力模拟,更好的方法是使用优先队列模拟。

时间复杂度

O

(

m

a

x

(

n

,

k

)

l

o

g

(

n

)

)

O(max(n,k)log(n))

O(max(n,k)log(n))
空间复杂度

O

(

n

)

O(n)

O(n)

参考代码

class Solution {
   public:
    long long pickGifts(vector<int>& a, int k) {
        priority_queue<int> q;
        for (auto it : a) {
            q.push(it);
        }
        while (k--) {
            int s = q.top();
            q.pop();
            s = sqrt(s);
            q.push(s);
        }
        long long ans = 0;
        while (q.size()) {
            ans += q.top();
            q.pop();
        }
        return ans;
    }
};

T2 统计范围内的元音字符串数

给定一个字符串数组,每次询问区间

[

l

,

r

]

[l,r]

[l,r]内,首尾字母都是元音字母的字符串数量。

预处理前缀和,差分询问。

时间复杂度

O

(

n

+

q

)

O(n+q)

O(n+q)
空间复杂度

O

(

n

)

O(n)

O(n)

参考代码

const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
class Solution {
   public:
    map<int, int> mp;
    bool check(string s) {
        return mp[s[0]] && mp[s.back()];
    }
    int sum[N];
    vector<int> vowelStrings(vector<string>& a, vector<vector<int>>& q) {
        mp['a'] = 1;
        mp['e'] = 1;
        mp['i'] = 1;
        mp['o'] = 1;
        mp['u'] = 1;
        int n = a.size();
        for (int i = 0; i < n; i++) {
            sum[i + 1] = sum[i] + check(a[i]);
        }
        vector<int> ans;
        for (auto it : q) {
            ans.emplace_back(sum[it[1] + 1] - sum[it[0]]);
        }
        return ans;
    }
};

T3 打家劫舍 IV

要求最大值最小,经典二分答案+

c

h

e

c

k

check

check

c

h

e

c

k

check

check 思路:二分出

m

i

d

mid

mid,贪心地线性检查能否取出

k

k

k 个价值

<

=

m

i

d

<=mid

<=mid 的房屋即可。

时间复杂度

O

(

n

l

o

g

(

m

)

)

O(nlog(m))

O(nlog(m))
空间复杂度

O

(

n

)

O(n)

O(n)

参考代码

const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;

class Solution {
   public:
    int minCapability(vector<int>& a, int k) {
        int n = a.size();
        int l = 1, r = 1e9, ans;
        while (l <= r) {
            int mid = (l + r) / 2;
            int pre = -2;
            int sum = 0;
            for (int i = 0; i < n; i++) {
                if (i - pre == 1) {
                    //不能相邻
                    continue;
                }
                if (a[i] <= mid) {
                    //选择
                    sum++;
                    pre = i;
                }
            }
            if (sum >= k) {
                r = mid - 1;
                ans = mid;
            } else {
                l = mid + 1;
            }
        }
        return ans;
    }
};

T4 重排水果

如下考虑:

  1. 判断原数组是否合法:两个数组排序后相同,则直接返回0。

  2. 判断是否存在解:将两个数组的元素混合在一起,如果某个元素为奇数个,那么一定无解。

  3. 剩下来的是必定有解,但需要交换的情况。
    首先去除他们的交集元素,现在数组

    a

    a

    a 和数组

    b

    b

    b 分别多了某些元素。根据每个元素的总数量,容易计算得到他们分别多出来

    x

    i

    x_i

    xi

    y

    i

    y_i

    yi,维护

    o

    u

    t

    a

    outa

    outa

    o

    u

    t

    b

    outb

    outb

    o

    u

    t

    a

    [

    x

    ]

    =

    y

    outa[x]=y

    outa[x]=y表示数组

    a

    a

    a

    x

    x

    x元素多了

    y

    y

    y个。
    考虑如何交换最优:
    ① 用数组

    a

    a

    a中的最小值和数组

    b

    b

    b中的最大值交换,花费为

    m

    i

    n

    (

    a

    m

    i

    n

    n

    ,

    b

    m

    a

    x

    x

    )

    min(a_{minn},b_{maxx})

    min(aminn,bmaxx)
    ② 用数组

    a

    a

    a中的最大值和数组

    b

    b

    b中的最小值交换,花费为

    m

    i

    n

    (

    b

    m

    i

    n

    n

    ,

    a

    m

    a

    x

    x

    )

    min(b_{minn},a_{maxx})

    min(bminn,amaxx)
    ③ 容易遗漏的一种情况,利用所有元素的最小值作为中间者,间接的交换

    a

    b

    ab

    ab中的元素:swap(a,c); swap(b,c);,因为

    c

    c

    c必定为最小值,且被用到了两次,因此花费为

    m

    i

    n

    n

    2

    minn*2

    minn2
    贪心地,如果数组

    a

    a

    a中的最小值

    <

    <

    <数组

    b

    b

    b中的最小值,则选用方案①③的组合,否则选用方案②③的组合。

时间复杂度

O

(

n

l

o

g

(

n

)

)

O(nlog(n))

O(nlog(n))
空间复杂度

O

(

n

)

O(n)

O(n)

参考代码

const int N = 1e5 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
class Solution {
   public:
    long long minCost(vector<int>& a, vector<int>& b) {
        int MINN = INF;
        map<int, int> mp, ma, mb;
        for (auto it : a) {
            mp[it]++, ma[it]++;
            MINN = min(MINN, it);
        }
        for (auto it : b) {
            mp[it]++, mb[it]++;
            MINN = min(MINN, it);
        }
        if (ma == mb) {
            // 已经合法
            return 0;
        }
        for (auto& it : mp) {
            if (it.second % 2) {
                // 某个元素总数量奇数个,不能平分
                return -1;
            }
            // 期望每个数组各有it.second个it.first
            it.second /= 2;
        }
        vector<pair<int, int>> outa, outb;
        int all = 0;
        for (auto it : mp) {
            int delta = ma[it.first] - it.second;
            // a中需要给出delta个it.first
            if (delta > 0) {
                // 总共需要给出all个
                all += delta;
                outa.emplace_back(make_pair(it.first, delta));
            }
            delta = mb[it.first] - it.second;
            // b中需要给出delta个it.first
            if (delta > 0) {
                outb.emplace_back(make_pair(it.first, delta));
            }
        }

        long long ans = 0;
        int n = outa.size();
        int ra = outa.size() - 1;
        int rb = outb.size() - 1;
        int la = 0;
        int lb = 0;

        while (all--) {
            if (!outa[la].second) {
                ++la;
            }
            if (!outa[ra].second) {
                --ra;
            }
            if (!outb[lb].second) {
                ++lb;
            }
            if (!outb[rb].second) {
                --rb;
            }
            if (outa[la].first < outb[lb].first) {
                outa[la].second--;
                outb[rb].second--;
                // 两种情况,借助最小值来间接交换 / 直接交换
                ans += min(min(MINN * 2, outa[la].first), outb[rb].first);
            }
            if (outa[la].first > outb[lb].first) {
                outa[ra].second--;
                outb[lb].second--;
                ans += min(min(MINN * 2, outa[ra].first), outb[lb].first);
            }
        }
        return ans;
    }
};

版权声明:本文为hesorchen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>