1723. 完成所有工作的最短时间

本文解析了一道关于分配工作的LeetCode题目,探讨了如何使用回溯算法找到最小的最大工作时间,并通过剪枝优化算法效率。最终采用了二分查找结合回溯的方法,实现了高效的解决方案。

题目链接:leetcode.

提示竟然用回溯,那不也是一种暴力?
hhhhhhh我就说嘛,怎么可能这么简单,超时啦,16 / 60 个通过测试用例

我不会了,大概需要剪枝吧

*求最大值max_element(jobs.begin(), jobs.end())

class Solution {
	int ans;
	vector<int> tmp;
	
	void dfs(const vector<int>& jobs, int k, int index)
	{
		if(index == jobs.size())
		{
			int maxx = 0;
			for(auto num : tmp)
			{
				maxx = max(maxx, num);//最大工作时间 
			}
			ans = min(ans, maxx);//最小的最大工作时间
			return; 
		}
		for(int i = 0;i < k;++i)
		{
			tmp[i] += jobs[index];
			dfs(jobs, k, index + 1);
			tmp[i] -= jobs[index];
		}
	}  
public:
    int minimumTimeRequired(vector<int>& jobs, int k) {
    	ans = INT_MAX;
    	tmp.resize(k, 0);
    	//人数和活一样多
		if(k == jobs.size())
		{
			auto maxPos = max_element(jobs.begin(), jobs.end());
			return *maxPos;
		} 
		//人比活少
    	dfs(jobs, k, 0);
    	return ans;
    }
};

参考题解多写了一句,结果还是超时 60 / 60 个通过测试用例
(先开始还不对呢,要先修改了tmp再判断跳不跳出,不然跳出来没修改回去,结果不对,而且这种情况最好排个序

class Solution {
	int ans;
	vector<int> tmp;
	
	void dfs(const vector<int>& jobs, int k, int index)
	{
		if(index == jobs.size())
		{
			int maxx = 0;
			for(auto num : tmp)
			{
				maxx = max(maxx, num);//最大工作时间 
			}
			ans = min(ans, maxx);//最小的最大工作时间
			return; 
		}
		for(int i = 0;i < k;++i)
		{
			tmp[i] += jobs[index];
			dfs(jobs, k, index + 1);
            tmp[i] -= jobs[index];
            //// 
			if(tmp[i] == 0)
			{
				break;
			} 
		}
	}  
public:
    int minimumTimeRequired(vector<int>& jobs, int k) {
    	ans = INT_MAX;
    	tmp.resize(k, 0);
    	//人数和活一样多
		if(k == jobs.size())
		{
			auto maxPos = max_element(jobs.begin(), jobs.end());
			return *maxPos;
		} 
		//人比活少
        sort(jobs.begin(), jobs.end());
    	dfs(jobs, k, 0);
    	return ans;
    }
};

官解的解决方式是,用二分查找
因为能满足最短时间为ans的组合,一定也能满足最短时间为limit (limit> ans)
查找那个最小的limit,左边界为数组最大值,右边界为数组和
对数组排序,先把工作时间长的给分配了

/*
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:7.2 MB, 在所有 C++ 提交中击败了70.05%的用户
*/
class Solution {
	bool dfs(const vector<int>& jobs, vector<int>& tmp, int limit, int index)
	{
		if(index >= jobs.size())
		{
			return true; 
		}
		//判断能不能所有工作时间都小于limit 
		for(int i = 0;i < tmp.size();++i)
		{
			if(tmp[i] + jobs[index] <= limit)
			{
				tmp[i] += jobs[index];
				if(dfs(jobs, tmp, limit, index + 1)) 
					return true;
				tmp[i] -= jobs[index];
			}
			//后面的都不对 或 当前为 0 或 已经到达limit且后面都不对
			//不必再试,剪枝
			if(tmp[i] == 0 || tmp[i] + jobs[index] == limit)
			{
				break;
			} 
		}
		return false;
	}  
	
	bool checkWork(const vector<int>& jobs, int k, int limit)
	{
		vector<int> tmp(k, 0);
		return dfs(jobs, tmp, limit, 0);
	} 
public:
    int minimumTimeRequired(vector<int>& jobs, int k) {
    	//人数和活一样多
		if(k == jobs.size())
		{
			auto maxPos = max_element(jobs.begin(), jobs.end());
			return *maxPos;
		} 
		//人比活少
        sort(jobs.begin(), jobs.end(), greater<int>());
        int left = jobs[0], right = accumulate(jobs.begin(), jobs.end(), 0);
        while(left < right)
        {
        	int mid = left + (right - left) / 2;
        	if(checkWork(jobs, k, mid))
        	{
        		right = mid;
        	}
        	else
        	{
        		left = mid + 1;
        	}
        }
    	return left;
    }
};

题解还有一个动态规划的方法,emmmm先不看了吧

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值