田忌赛马背后的算法决策 :: labuladong的算法小抄 #1014
Replies: 31 comments 15 replies
-
Beta Was this translation helpful? Give feedback.
-
class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 田忌赛马问题
hq = []
# 大顶堆
for i, num in enumerate(nums2):
heapq.heappush(hq, (-num, i))
nums1.sort()
# 双指针
left, right = 0, len(nums1) - 1
res = [0] * len(nums1)
while hq:
max_num, idx = heapq.heappop(hq)
max_sum = -max_num
if max_sum < nums1[right]:
res[idx] = nums1[right]
right -= 1
else:
res[idx] = nums1[left]
left += 1
return res |
Beta Was this translation helpful? Give feedback.
-
Python解法,空间使用超过99%+,没有用到堆,只用了二分搜索和排序 class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
def helper(idx):
left, right = 0, len(nums1)-1
while left <= right:
mid = (left + right) // 2
if nums1[mid] > nums2[idx]:
right = mid - 1
else:
left = mid + 1
if left < len(nums1):
temp = left
else:
temp = 0
ans.append(nums1[temp])
nums1.pop(temp)
nums1.sort()
visited = [False] * len(nums1)
ans = []
for i in range(len(nums2)):
helper(i)
return ans |
Beta Was this translation helpful? Give feedback.
-
try this case: |
Beta Was this translation helpful? Give feedback.
-
@Xiaoyuan-Liu 没问题,这道题的答案并不唯一 |
Beta Was this translation helpful? Give feedback.
-
有一个小问题,就是PriorityQueue的构造方法为啥可以只有比较器,我一直没找到这种构造方法,但是我看网上都是直接用的,困扰我好久了 |
Beta Was this translation helpful? Give feedback.
-
@LakersHao java的话建议直接按住ctrl点进PriorityQueue的源码,可以看到有7个构造器,其中有一个是 |
Beta Was this translation helpful? Give feedback.
-
这个case没过 |
Beta Was this translation helpful? Give feedback.
-
go实现,大顶堆解法会有一个case不通过,换成sort直接两边排序可以ac import (
"container/heap"
"sort"
)
// @lc code=start
func advantageCount(nums1 []int, nums2 []int) []int {
// sort.Ints(nums1)
// b := make([][2]int, len(nums2))
// for i, n := range nums2 {
// b[i] = [2]int{n, i}
// }
// sort.Slice(b, func(i, j int) bool {
// return b[i][0] < b[j][0]
// })
// result := make([]int, len(nums1))
// left, right := 0, len(nums1)-1
// for i := len(b) - 1; i >= 0; i-- {
// val, idx := b[i][0], b[i][1]
// if nums1[right] > val {
// result[idx] = nums1[right]
// right--
// } else {
// result[idx] = nums1[left]
// left++
// }
// }
// return result
// nums1 升序排列
sort.Ints(nums1)
// nums2 降序排序,大顶堆
h := make(IntHeap, 0)
for i, val := range nums2 {
h = append(h, []int{i, val})
}
heap.Init(&h)
l, r := 0, len(nums1)-1
res := make([]int, len(nums1))
for h.Len() > 0 {
pair := h.Pop()
i, max := (pair.([]int))[0], (pair.([]int))[1]
if max < nums1[r] {
// 如果nums1[r]大于max,那就填入这个值
res[i] = nums1[r]
r--
} else {
// 否则用最小最混一下,田忌赛马
res[i] = nums1[l]
l++
}
}
return res
}
// 大顶堆,实现heap的interface
// h[x][0] 存储 index,h[x][1] 存储 value
type IntHeap [][]int
// 绑定Len方法
func (h IntHeap) Len() int {
return len(h)
}
// 绑定Less方法,这里用的是小于号,生成的是小根堆
func (h IntHeap) Less(i, j int) bool {
return h[i][1] > h[j][1]
}
// 绑定swap方法
func (h IntHeap) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
// pop、push 使用指针,因为改变了slice长度
// 绑定put方法,将index置为-1是为了标识该数据已经出了优先级队列了
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
item := old[0]
*h = old[1:n]
return item
}
// 绑定push方法
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.([]int))
}
// @lc code=end |
Beta Was this translation helpful? Give feedback.
-
不用PQ可以么,直接Desend排序nums2? |
Beta Was this translation helpful? Give feedback.
-
打卡 |
Beta Was this translation helpful? Give feedback.
-
相等的情况呢?如果田忌是【8,6】,齐王是【8,7】,那么8=8的时候换6来打是可以的,优势增大;如果齐王是【8,5】呢,那样本来可以平一局赢一局的,结果变成输一局赢一局,优势减小了吧。所以相等情况是不是要根据下一个的值大小比较来确定顺序 |
Beta Was this translation helpful? Give feedback.
-
在看文章前尝试自己做了下这道题,对于排序后导致顺序错乱问题,可以写一个类来解决。对于两组马都按照战力值升序排列: class Solution {
class Horse {
int pos, weight;
boolean used;
}
public int[] advantageCount(int[] nums1, int[] nums2) {
int n = nums1.length;
int[] ans = new int[n];
Horse[] horses1 = new Horse[n];
Horse[] horses2 = new Horse[n];
for (int i = 0; i < n; i++) {
horses1[i] = new Horse();
horses1[i].pos = i;
horses1[i].weight = nums1[i];
horses2[i] = new Horse();
horses2[i].pos = i;
horses2[i].weight = nums2[i];
}
Arrays.sort(horses1, Comparator.comparingInt(o -> o.weight));
Arrays.sort(horses2, Comparator.comparingInt(o -> o.weight));
int p1 = 0, p2 = 0;
while (p1 < n) {
if (horses1[p1].weight > horses2[p2].weight) {
ans[horses2[p2].pos] = horses1[p1].weight;
horses1[p1].used = true;
horses2[p2].used = true;
p1++; p2++;
} else {
p1++;
}
}
p2 = n - 1;
// 从后往前找
for (int i = horses1.length - 1; i >= 0; i--) {
if (!horses1[i].used) {
while (ans[horses2[p2].pos] != 0) p2--;
ans[horses2[p2].pos] = horses1[i].weight;
}
}
return ans;
}
} |
Beta Was this translation helpful? Give feedback.
-
Test Case
我的 答案 #我的不比答案好?还是有什么我遗漏了? |
Beta Was this translation helpful? Give feedback.
-
class Solution:
def advantageCount(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1_ = sorted(nums1)
nums2_ = sorted(enumerate(nums2), key=lambda p: p[1])
left = 0
right = len(nums1) - 1
res = [-1] * len(nums1)
while nums2_:
i, maxval = nums2_.pop()
if maxval < nums1_[right]:
res[i] = nums1_[right]
right -= 1
else:
res[i] = nums1_[left]
left += 1
return res |
Beta Was this translation helpful? Give feedback.
-
20230110 打卡。田忌赛马的思想真牛 |
Beta Was this translation helpful? Give feedback.
-
js写法,时间复杂度O(nlogn)
|
Beta Was this translation helpful? Give feedback.
-
优势洗牌里面chatgpt给出的c++解法有问题,一是语法错误(priority_queue在插入数据时没有make_pair),二是没有重载运算符,导致priority_queue进行排序时按照第一个数字i排序, /*
* @lc app=leetcode.cn id=870 lang=cpp
*
* [870] 优势洗牌
*/
// @lc code=start
class Solution {
public:
vector<int> advantageCount(vector<int> &nums1, vector<int> &nums2) {
priority_queue<pair<int, int>> maxpl;
for (int i = 0; i < nums1.size(); i++) {
maxpl.push(make_pair(nums2[i],i));
}
int left = 0, right = nums1.size() - 1;
vector<int> res(nums1.size());
sort(nums1.begin(), nums1.end());
while (!maxpl.empty()) {
auto [maxp,i] = maxpl.top();
maxpl.pop();
if (nums1[right] > maxp) {
res[i] = nums1[right];
cout<<res[i]<<maxp<<i<<endl;
right--;
} else {
res[i] = nums1[left];
cout<<res[i]<<maxp<<i<<endl;
left++;
}
}
return res;
}
};
// @lc code=end |
Beta Was this translation helpful? Give feedback.
-
chatgpt给出的js解法前半部分有些问题, 更正了下
|
Beta Was this translation helpful? Give feedback.
-
打卡,附上详细注解的Java代码 //算法的思路其实很简单:如果我们两个最好的比较nums1可以干过nums2,那就让nums1最好的上,否则让nums1中最差的去送人头
public int[] advantageCount(int[] nums1, int[] nums2) {
int n=nums1.length;
//对nums1进行一个排序,升序排列
Arrays.sort(nums1);
//因为nums2是不能改变顺序的,我们是和nums2进行对弈的,所以使用一个辅助数据结构来存储排序的结构
//优先级队列中自定义了比较规则从大到小排列了,每个节点存储的结构是[索引,值]
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((int[] pair1, int[] pair2) -> {
return pair2[1] - pair1[1];
});
for (int i = 0; i < nums2.length; i++) {
priorityQueue.offer(new int[]{i,nums2[i]});
}
//两个人开始对弈
int left=0,right=n-1;
int[] res=new int[n];
while(!priorityQueue.isEmpty()){
int[] poll = priorityQueue.poll();
if(nums1[right]>poll[1]){
//nums1中最好的可以打过nums2中最好的,直接干
//结果的位置要根据nums2的索引顺序来确定,因为是和nums2进行对弈的
res[poll[0]]=nums1[right];
right--;
}else{
//干不过,让最差的去送
res[poll[0]]=nums1[left];
left++;
}
}
return res;
} |
Beta Was this translation helpful? Give feedback.
-
补充一个cpp的版本,东哥这里的cpp版本答案有点偏差: |
Beta Was this translation helpful? Give feedback.
-
博主的c++代码存在错误,maxpq的顺序因为nums2[i],i 因为队列以第一个元素排大小。 |
Beta Was this translation helpful? Give feedback.
-
更新一下pass的cpp代码,如果用chatgpt翻译过来的cpp不太正确。 class Solution {
public:
vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size();
// 给 nums2 升序排序
priority_queue<pair<int, int>> maxpq;
for (int i = 0; i < n; i++) {
maxpq.emplace(nums2[i] , i);
}
// 给 nums1 升序排序
sort(nums1.begin(), nums1.end());
// nums1[left] 是最小值,nums1[right] 是最大值
int left = 0, right = n - 1;
vector<int> res(n);
while (!maxpq.empty()) {
auto [maxval, i] = maxpq.top();
maxpq.pop();
if (maxval < nums1[right]) {
// 如果 nums1[right] 能胜过 maxval,那就自己上
res[i] = nums1[right];
right--;
} else {
// 否则用最小值混一下,养精蓄锐
res[i] = nums1[left];
left++;
}
}
return res;
}
}; |
Beta Was this translation helpful? Give feedback.
-
妙哉,妙哉 |
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
-
我想到的思路是从最差的马开始找,各自从所有未分配比赛的马中找一匹最差的马,如果田忌能赢,就用这匹马,这样用最差的马来获取胜利是最“节约“的办法。如果田忌不能赢,因为这匹马必然不会带来任何一场胜利,因此就让他去与齐王最厉害的马比赛,然后再比较当前田忌最差的马能否嬴齐王最差的马,以此类推,直到所有的马都被分配比赛。 |
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
-
cpp的代码错了,因为优先队列没有自定义排序 |
Beta Was this translation helpful? Give feedback.
-
非常感谢您的邮件。
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
文章链接点这里:田忌赛马背后的算法决策
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions