870. 优势洗牌

地址:

力扣icon-default.png?t=M1L8https://leetcode-cn.com/problems/advantage-shuffle/

题目:

给定两个大小相等的数组 A 和 B,A 相对于 B 的优势可以用满足 A[i] > B[i] 的索引 i 的数目来描述。

返回 A 的任意排列,使其相对于 B 的优势最大化。

示例 1:

输入:A = [2,7,11,15], B = [1,10,4,11]
输出:[2,11,7,15]


示例 2:

输入:A = [12,24,8,32], B = [13,25,32,11]
输出:[24,32,8,12]
 

提示:

1 <= A.length = B.length <= 10000
0 <= A[i] <= 10^9
0 <= B[i] <= 10^9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/advantage-shuffle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

本题其实就是田忌赛马

对于 A ,B 两个数组,有可能 升序后, A 全部都大于 B;也有可能部分大于或者完全不大于

以 A = [12,24,8,32], B = [13,25,32,11] 为例子:

排序后 A =[8,12,24,32],B =[11,13,25,32] 部分大于

 

我们来推演过程:

1. A[0] =8 与 B[0] = 11 比较,不满足A > B,忽略 A 的 8

2. A 的下一个元素继续比较,大于,那么匹配成一对

3. 同理,后续匹配情况

4. 最后一定剩余不匹配的,这个时候无所谓,依序匹配就是

整个匹配按照 A 元素依序比较 B 元素,因为做了排序,所以是在 A 元素的最小值刚好大于 B 元素的匹配。如果拿更大的A匹配B,就不划算。

方法一、贪心

最后的输出一定是按照 B 的原始序号匹配输出,但是我们的比较是做了排序的,那么势必要保存 B 的原始序号,所以自定义个结构体来保存 B 的信息。

最后匹配信息也会填入这个结构体,全部完成后,再依据 存的 idx 栏位升序排列,输出匹配的值即可

typedef struct {
    int val;    // orig val
    int idx;    // orig idx
    int mval;   // matched val
}KEYVAL;

int cmpKeyVal(const KEYVAL *a, const KEYVAL *b)
{
    return a->val - b->val;
}

int cmpKeyIdx(const KEYVAL *a, const KEYVAL *b)
{
    return a->idx - b->idx;
}

int cmpInt(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}

void dispKeyvalArr(KEYVAL *arr, int arrlen)
{
    for(int i=0; i<arrlen; i++)
        printf("val=%d,idx=%d,mval=%d\n", arr[i].val, arr[i].idx, arr[i].mval);
}

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* advantageCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){
    int i,j;
    
    KEYVAL *bArr = (KEYVAL *)malloc(sizeof(KEYVAL) * nums2Size);
    
    for(i=0; i<nums2Size; i++)
    {
        bArr[i].val = nums2[i];
        bArr[i].idx = i;
        bArr[i].mval = -1;
    }

    //dispKeyvalArr(bArr, nums2Size);
    // sore by val
    qsort(bArr, nums2Size, sizeof(KEYVAL), cmpKeyVal);
    //dispKeyvalArr(bArr, nums2Size);

    qsort(nums1, nums1Size, sizeof(int), cmpInt);
    // for(i=0; i<nums1Size; i++)
    // {
    //     printf("nums1[%d]=%d\n", i, nums1[i]);
    // }

    int k = 0;
    int umNum = 0; // un-matched number
    for(i=0, j=0; i<nums1Size; i++)
    {
        if(nums1[i] <= bArr[j].val)
        {
            //printf("unmatch...nums1[%d]=%d, bArr[%d].val=%d\n", i, nums1[i], j, bArr[j].val);
            nums2[k++] = nums1[i];   // re-use nums2 to restore un-match elements
            umNum++;
        }
        else
        {
            bArr[j++].mval = nums1[i];
        }
    }

    k = 0;
    while(umNum--)
    {
        bArr[j++].mval = nums2[k++];
    }
    //dispKeyvalArr(bArr, nums2Size);

    // sore by idx
    qsort(bArr, nums2Size, sizeof(KEYVAL), cmpKeyIdx);
    //dispKeyvalArr(bArr, nums2Size);

    // return new nums1
    for(i=0, j=0; i<nums1Size; i++)
        nums1[i] = bArr[i].mval;

    *returnSize = nums1Size;
    return nums1;
}

 查看更多刷题笔记

<think>嗯,用户问的是关于通道洗牌(Channel Shuffle)的概念和实现方法,特别是在ShuffleNet中的应用。首先,我需要回忆一下ShuffleNet的基本结构和通道洗牌的作用。记得ShuffleNet是为了轻量化模型设计的,主要用了深度可分离卷积和通道洗牌。通道洗牌的主要目的是解决分组卷积带来的信息流通问题,对吧? 接下来,我得确认通道洗牌的具体实现步骤。根据之前的资料,通道洗牌通常是在分组卷积之后,通过重新排列通道来促进不同组之间的信息交换。比如,假设有G个组,每个组有K个通道,总共有G×K个通道。那么,将通道reshape成(G, K)的矩阵,然后转置为(K, G),再展平回去,这样每个组里就会有来自不同原始组的通道,这样后续的卷积操作就能混合不同组的信息了。 然后要考虑用户可能的背景。用户可能对深度学习中的轻量化模型有一定了解,比如MobileNet,但可能对ShuffleNet的细节不太清楚。他们可能想知道通道洗牌为什么有效,以及具体的实现方式。此外,用户可能对代码实现感兴趣,需要提供一个简洁的PyTorch示例。 还要注意引用相关的参考文献,特别是引用[2]、[3]、[4]中提到的通道洗牌的作用和实现方法。需要确保引用的正确性,比如提到通道洗牌如何减少计算量同时保持性能,以及ShuffleNet的设计目标。 另外,用户可能没有直接说出但潜在的问题可能包括:通道洗牌和普通shuffle的区别,为什么分组卷积需要通道洗牌,以及通道洗牌对模型准确率的影响。所以在相关问题部分,可以设计这些问题,帮助用户更深入理解。 最后,要确保回答结构清晰,分点解释概念、步骤、作用,并附上代码示例和相关问题。同时检查LaTeX格式是否正确,行内公式用$...$,独立公式用$$...$$,并正确标注引用。</think>### 通道洗牌(Channel Shuffle)详解 #### 1. 概念与背景 通道洗牌是ShuffleNet系列网络的核心操作,旨在解决分组卷积(Group Convolution)导致的**通道信息隔离**问题。在轻量化网络设计中,分组卷积可大幅降低计算量,但若多个分组卷积层堆叠,各组的通道信息无法交互,导致特征表达能力下降。通道洗牌通过**重新排列通道顺序**,使不同组的特征信息交叉融合,提升模型的非线性表达能力[^2][^3]。 #### 2. 算法实现步骤 1. **输入特征图划分组**:假设输入特征图尺寸为$C \times H \times W$(通道数×高度×宽度),将其按通道划分为$G$组,每组含$C/G$个通道。 2. **通道维度变换**: - 将通道维度$C$转换为$(G, C/G)$的二维矩阵。 - 转置该矩阵为$(C/G, G)$。 - 重新展平为一维通道序列。 3. **特征交叉**:转置操作使不同组的通道交错排列,后续卷积层可跨组提取特征。 以代码为例(PyTorch实现): ```python def channel_shuffle(x, groups): batch_size, num_channels, height, width = x.size() channels_per_group = num_channels // groups # Reshape为 (batch_size, groups, channels_per_group, H, W) x = x.view(batch_size, groups, channels_per_group, height, width) # 转置维度1和2 -> (batch_size, channels_per_group, groups, H, W) x = x.transpose(1, 2).contiguous() # 展平回原始维度 return x.view(batch_size, -1, height, width) ``` #### 3. 作用与优势 - **提升特征交互**:打破分组卷积的通道壁垒,增强模型非线性[^3]。 - **轻量化设计**:与深度可分离卷积结合,计算量仅为标准卷积的$1/9$[^1]。 - **精度保障**:在ImageNet分类任务中,ShuffleNet在同等计算量下比MobileNet精度提升1.5%[^4]。 #### 4. 应用场景 - 移动端/嵌入式设备的实时图像分类 - 目标检测轻量化Backbone(如YOLO-Lite) - 视频分析中的高效特征提取
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值