bigpotato

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.

If there are multiple solutions, return any subset is fine.

Example 1:

nums: [1,2,3]

Result: [1,2] (of course, [1,3] will also be ok)

Example 2:

nums: [1,2,4,8]

Result: [1,2,4,8]

 

给定一个数组,其元素均为正整数,找出元素最多的这样一个子数组:该数组任意两个元素(设为Si,Sj),满足Si%Sj==0或Sj%Si==0。若存在多种满足条件的子数组,返回其中任意一个均可。

分析:

  设原数组有n个元素(s1,s2,…,sn),并记为Sn,设其满足条件的最大子集为Rn。取Sn前n-1个元素构成的子集Sn-1,设其满足条件的最大子集为Rn-1。不难得出,若sn与Rn-1中任一元素ri满足sn%ri==0或ri%sn==0,则Rn=(Rn-1,sn);否则Rn=Rn-1,记Rn={Rn-1,sn}。而Rn-1={Rn-2,sn-1},不停迭代,可知Rn={{{{R1,s0},s1},…},sn}。这是典型的动态规划问题,可用动态规划来求解。为简便起见,先将输入数组S按元素从小到大的顺序排序。遍历数组S,用数组dp来记录每取一个元素时满足条件的最大子集的长度,如dp[i]表示数组S前i个元素构成的子数组的满足条件的最大子数组的长度;另用一个数组prev来记录最大子数组的当前元素的前一个元素的索引,以便后续查找出最大子数组。遍历完成后,遍历数组dp,找出最大子数组的长度maxlen,并记录其最后一个元素的索引idx。最后,根据索引数组prev,从原数组S中取出最大子数组即可。

代码如下:

vector<int> largestDivisibleSubset(vector<int>& nums)
{
	vector<int> rst;
	if (nums.empty())
		return rst;
	int cnt = nums.size();
	vector<int> dp(cnt, 0);
	vector<int> prev(cnt, 0);
	int maxlen = 0, idx = 0;
	sort(nums.begin(), nums.end());
	for (int i = 1; i < cnt; i++)
	{
		for (int j = i - 1; j >= 0; j--)
		{
			if (nums[i] % nums[j] == 0 && dp[i] < dp[j] + 1)
			{
				dp[i] = dp[j] + 1;
				prev[i] = j;
			}
		}
	}
	for (int i = 0; i < cnt; i++)
	{
		if (maxlen < dp[i])
		{
			maxlen = dp[i];
			idx = i;
		}
	}
	for (int i = idx; i >= 0, maxlen >= 0;)
	{
		rst.push_back(nums[i]);
		i = prev[i];
		maxlen--;
	}
	sort(rst.begin(), rst.end());
	return rst;
}

  

posted on 2018-03-23 09:04  bigpotato  阅读(210)  评论(0)    收藏  举报