首页 > 编程语言 >算法编程题-优势洗牌

算法编程题-优势洗牌

时间:2024-11-29 14:59:55浏览次数:7  
标签:洗牌 int res 复杂度 编程 rbtree 算法 nums1 nums2

算法编程题-优势洗牌


摘要:本文将对LeetCode原题优势洗牌进行介绍,从最容易想到的方法开始,循序渐进,一步步优化,对于每一种方法,都给出基于golang语言实现的且通过所有测试用例的完整代码,并且给出相应的复杂度分析。
关键词:LeetCode,面试,排序,贪心,golang

原题描述

给定两个整数数组nums1和nums2,要求给出nums1数组的一个排列,使其相比于nums2的优势最大化,所谓的优势指的就是nums1对应位置大于nums2对应位置的个数。

方法一、排序+二分查找

思路简述

从贪心的角度出发,对于nums2每一个数(相当于是一个对手),nums1这边应该尽可能派出最弱但是又能战胜对方的,因此可以对于nums1排序,基于二分查找从nums1中找最小的大于nums2对应位置的数,如果没有,则取nums1中最小的数应战。但是由于一个数只能用一次,所以要从nums1中删除出战的数字。

代码实现

func advantageCount(nums1 []int, nums2 []int) []int {
    sort.Slice(nums1, func(i, j int) bool {
		return nums1[i] < nums1[j]
	})
	n := len(nums1)
	res := make([]int, 0, n)
	for i := 0; i < n; i++ {
		pos := findMinLarger(nums1, nums2[i])
		if pos == -1 {
			pos = 0
		}
		res = append(res, nums1[pos])
		nums1 = append(nums1[: pos], nums1[pos + 1:]...)
	}
	return res
}


func findMinLarger(nums []int, target int) int {
	n := len(nums)
	low := 0
	high := n - 1
	for low < high {
		mid := (low + high) / 2
		if nums[mid] > target {
			high = mid
		} else {
			low = mid + 1
		}
	}
	if nums[low] > target {
		return low
	}
	return -1
}

LeetCode运行截图如下:
在这里插入图片描述

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),因为移除元素这个操作,需要移动数组中的元素,所以每一次选择出战数字的复杂度都是 O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

方法二、红黑树

思路简述

考虑如何优化上一种做法的时间复杂度,遍历的 O ( n ) O(n) O(n)时间复杂度是肯定没有办法优化的,那么删除元素这个操作呢?有没有什么数据结构支持对于数据的增删改查时间复杂度都是 O ( l o g n ) O(logn) O(logn),且可以方便地进行范围查询,答案其实有很多,比如说跳表,AVL树,红黑树甚至B+树也是可以的。我们这里以红黑树为例来说明这个问题。由于golang标准库中没有红黑树这个数据结构,但是LeetCode针对golang语言提前导入了一个第三方的数据结构包,可以使用其中的红黑树实现。但是这个红黑树在实现这个问题上有很多难受的地方,一个是题目中的数组中是有重复数字的,而这个红黑树数字是不允许重复的,二是这个提供的接口ceiling取的是最小的大于等于某个数的开销,这个由于数组里面是整数,可以通过将目标值加一再去查找解决。具体参考以下的代码实现。

代码实现

import (
    rbt "github.com/emirpasic/gods/trees/redblacktree"
)


func advantageCount(nums1 []int, nums2 []int) []int {
	rbtree := rbt.NewWithIntComparator()
	for _, num := range nums1 {
		incrRbtree(rbtree, num)
	}
	n := len(nums2)
	res := make([]int, 0, n)
	for i := 0; i < n; i++ {
		node, found := rbtree.Ceiling(nums2[i] + 1)
		if found {
			res = append(res, node.Key.(int))
			decrRbtree(rbtree, node.Key.(int))
		} else {
            res = append(res, -1)
        }
	}

    remainVals := make([]int, 0, n)
    keys := rbtree.Keys()
    k := 0
    for j := range keys {
        key := keys[j].(int)
        var c int
        ret, found := rbtree.Get(key)
        if !found {
            c = 0
        } else {
            c = ret.(int)
        }
        for i := 0; i < c; i++ {
            remainVals = append(remainVals, key)
        }
    }
    for i := range res {
        if res[i] == -1 {
            res[i] = remainVals[k]
            k++
        }
    }
	return res
}

func incrRbtree(rbtree *rbt.Tree, val int) {
    var count int
    ret, found := rbtree.Get(val)
    if !found {
        count = 0
    } else {
        count = ret.(int)
    }
    rbtree.Put(val, count + 1)
}

func decrRbtree(rbtree *rbt.Tree, val int) {
    var count int
    ret, found := rbtree.Get(val)
    if !found {
        return
    } else {
        count = ret.(int)
    }
    if count == 1 {
        rbtree.Remove(val)
        return
    }
    rbtree.Put(val, count - 1)
}

LeetCode运行截图如下:
在这里插入图片描述

复杂度分析

  • 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
  • 空间复杂度: O ( n ) O(n) O(n)

方法三、贪心

思路简述

换一种贪心策略,按照田忌赛马的思路去想,如果我方当前的最弱马强于对方最弱马,那就用最弱马去对战最弱马,否则去对战对方的最强马。具体过程参考代码实现。

代码实现

func advantageCount(nums1 []int, nums2 []int) []int {
    sort.Slice(nums1, func(i, j int) bool {
		return nums1[i] < nums1[j]
	})
    n := len(nums1)
    // nums2不能排序
    idxs := make([]int, n)
    for i := 0; i < n; i++ {
        idxs[i] = i
    }
    sort.Slice(idxs, func(i, j int) bool {
        return nums2[idxs[i]] < nums2[idxs[j]]
    })
	res := make([]int, n)
    k := n - 1
    j := 0
	for _, num := range nums1 {
        if num > nums2[idxs[j]] {
            res[idxs[j]] = num
            j++
        } else {
            res[idxs[k]] = num
            k--
        }
    }
	return res
}

LeetCode运行截图如下:
在这里插入图片描述

复杂度分析

  • 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
  • 空间复杂度: O ( n ) O(n) O(n)

标签:洗牌,int,res,复杂度,编程,rbtree,算法,nums1,nums2
From: https://blog.csdn.net/rtffcggh/article/details/144135465

相关文章

  • AI编程的新思维与技术挑战
    人工智能,深度学习,神经网络,编程思维,算法设计,机器学习1.背景介绍人工智能(AI)正以惊人的速度发展,深刻地改变着我们生活的方方面面。从自动驾驶汽车到智能语音助手,从医疗诊断到金融预测,AI技术的应用场景日益广泛。然而,与传统软件开发相比,AI编程面临着独特的挑战。传统的软......
  • 【MATLAB源码-第208期】基于matlab的改进A*算法和传统A*算法对比仿真;改进点:1.无斜穿障
    操作环境:MATLAB2022a1、算法描述改进A*算法的优点分析改进A*算法相对于传统A*算法在多个方面进行了优化,包括避免斜穿障碍物顶点、删除中间多余节点以及提高搜索效率。这些改进措施使得路径规划更加高效、安全和可靠,特别是在复杂环境中表现尤为突出。本文将详细讨论这些改......
  • MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元多输入单输出回归预测
    目录MATLAB实现POA-CNN-GTR鹈鹕算法优化卷积门控循环单元多输入单输出回归预测...1项目背景介绍...1项目目标与意义...2项目挑战...2项目特点与创新...3项目应用领域...3项目效果预测图程序设计...4项目模型架构...5项目模型描述...5项目模型算法流程图.........
  • MATLAB实现TSO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测(多指标,多图)
    目录MATLAB实现TTO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测(多指标,多图)    1项目背景介绍...1项目目标与意义...2项目挑战...2项目特点与创新...2项目应用领域...3项目效果预测图程序设计...3项目模型架构...4项目模型描述...4项目结构......
  • 如何让项目更轻松、高效?时间的“敌人”与“朋友” —— 编程界的“梗”与实践
    引言:时间,是程序员的最大敌人?作为程序员,我们总是面临“时间”这个问题——不够、浪费、失去。这不仅是日常工作中的挑战,还是技术决策中的隐形敌人。“时间”,它不仅仅是个概念,它还是程序中的“bug”之一。就像一颗定时炸弹,它能在不知不觉间埋下一个小小的隐患,等到某个点爆......
  • 代码随想录算法训练营第二十九天| leetcode134. 加油站、leetcode135.分发糖果、leetc
    1leetcode134.加油站题目链接:134.加油站-力扣(LeetCode)文章链接:代码随想录视频链接:贪心算法,得这么加油才能跑完全程!LeetCode:134.加油站_哔哩哔哩_bilibili思路:其实这道题我有思路了,但是不知道怎么写,感觉太暴力了,就是找到花费最小的那个位置且汽油足够往下走的地方,开始走,......
  • 早鸟票开启:2025年计算机应用、图像处理与视觉算法国际学术会议(CAIPVA2025)
    #学术会议早知道##早鸟价优惠#2025年计算机应用、图像处理与视觉算法国际学术会议(CAIPVA2025)2025InternationalConferenceonComputerApplications,ImageProcessing,andVisionAlgorithms重要信息会议地点:中国·昆明会议时间:2025年2月21-23日一轮论文提交日期:20......
  • 两位数13和62具有很有趣的性质:把它们个位数字和十位数字对调,其乘积不变,即13*62=31*26
    /*下面的是我自己写的,运行结果为64不知道是否正确*/#include<stdio.h>intmain(){ inti,j,count[90],oppsite[90],k=0,m=0;//count[90]放两位数,oppsite[90]放对调后的数 for(i=1;i<=9;i++) { for(j=0;j<=9;j++)  if(i!=j)  {  count[k]=i*10+j; ......
  • 程序化交易编程语言有哪些常见选择?
    Python股票接口实现查询账户,提交订单,自动交易(1)Python股票程序交易接口查账,提交订单,自动交易(2)股票量化,Python炒股,CSDN交流社区>>>Python是一种非常流行的编程语言,在程序化交易领域也备受青睐。它具有简洁的语法,这使得代码易于编写和理解。对于初学者来说,学习曲线较为平......
  • 页面置换算法
    页面置换算法‍​​‍页面的换入、换出需要磁盘I/O,会有较大的开销,因此好的页面置换算法应该追求更少的缺页率。一、OPT最佳置换算法Optimal每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。​​理解:该算法虽然性能最......