【解题报告】《九日集训》(第五天)

语言:C++

912. 排序数组

912. 排序数组

给你一个整数数组 nums,请你将该数组升序排列。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

调用库函数

不过显然:被划分为中等题的目的是为了让自己实现排序

class Solution
{
public:
    vector<int> sortArray(vector<int>& nums) 
    {
        sort(nums.begin(), nums.end());
        return nums;
    }
};

归并排序

写Merge的时候少写了&,给孩子整蒙了,耽搁了好久

顺便推荐一下我发过的八大排序

class Solution
{
public:
	void Merge(vector<int>& arr, int len, int gap)
	{
		int low1 = 0;
		int high1 = low1 + gap - 1;
		int low2 = high1 + 1;
		int high2 = low2 + gap < len ? low2 + gap - 1 : len - 1;
		vector<int>brr(len);
		int i = 0;//brr的下标
		//有两个归并段
		while (low2 < len)
		{
			//两个归并段还有数据,需要比较
			while (low1 <= high1 && low2 <= high2)
			{
				if (arr[low1] < arr[low2])
				{
					brr[i++] = arr[low1++];
				}
				else
				{
					brr[i++] = arr[low2++];
				}
			}

			//一个归并段已经完成,另一个还有数据
			while (low1 <= high1)
			{
				brr[i++] = arr[low1++];
			}

			while (low2 <= high2)
			{
				brr[i++] = arr[low2++];
			}

			//4个变量往后走,下两个归并段
			low1 = high2 + 1;
			high1 = low1 + gap - 1;
			low2 = high1 + 1;
			high2 = low2 + gap < len ? low2 + gap - 1 : len - 1;
		}

		//只有一个归并段
		while (low1 < len)
		{
			brr[i++] = arr[low1++];
		}

		//brr数据复制到arr中
		arr = brr;
	}

	vector<int> sortArray(vector<int>& nums)
	{
		for (int i = 1; i < nums.size(); i *= 2)
		{
			Merge(nums, nums.size(), i);
		}
		return nums;
	}
};

169. 多数元素

169. 多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:[3,2,3]
输出:3

哈希

「时间复杂度O(n),空间复杂度O(n)」

class Solution
{
public:
    int majorityElement(vector<int>& nums)
    {
        unordered_map<int, int>hash;
        for (auto m : nums)
        {
            hash[m]++;
            if (hash[m] > nums.size() / 2)
                return m;
        }
        return -1;
    }
};

Boyer-Moore 投票算法(摩尔投票算法)

「时间复杂度O(n),空间复杂度O(1」

class Solution 
{
public:
	int majorityElement(vector<int>& nums)
	{
		int count = 1;
		int tmp;
		for (int i=0;i<nums.size();++i)
		{
			if (i == 0)
				tmp = nums[0];
			else
			{
				if (nums[i] == tmp)
				{
					count++;
				}
				else
				{
					count--;
					if (count == 0)
					{
						tmp = nums[i];
						count = 1;
					}
					else if (count > nums.size() / 2)
					{
						break;
					}
				}
			}
		}
        return tmp;
	}
};

优化了一下

class Solution 
{
public:
	int majorityElement(vector<int>& nums)
	{
		int count =0;
		int tmp=nums[0];
		for (auto n:nums)
		{
			if (n == tmp)
				count++;
			else
			{
				if (--count == 0)
				{
					tmp = n;
					count = 1;
				}
				if (count > nums.size() / 2)
				{
					break;
				}
			}			
		}
		return tmp;
	}
};

217. 存在重复元素

217. 存在重复元素

给定一个整数数组,判断是否存在重复元素。

如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false

示例 1:

输入: [1,2,3,1]
输出: true

哈希

class Solution
{
public:
    bool containsDuplicate(vector<int>& nums) 
    {
        unordered_map<int, int>hash;
        for (auto n : nums)
        {
            if (++hash[n] == 2)
                return true;           
        }
        return false;
    }
};

排序

class Solution
{
public:
	bool containsDuplicate(vector<int>& nums)
	{
		sort(nums.begin(), nums.end());
		for (int i = 0; i < nums.size() - 1; i++)
		{
			if (nums[i] == nums[i + 1])
			{
				return true;
			}
		}
		return false;
	}
};

164. 最大间距

164. 最大间距

给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。

如果数组元素个数小于 2,则返回 0。

示例 1:

输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。

调用库函数

class Solution
{
public:
	int maximumGap(vector<int>& nums)
	{
		if (nums.size() < 2)
			return 0;
		sort(nums.begin(), nums.end());
		int max = INT_MIN;
		for (int i = 0; i < nums.size() - 1; i++)
		{
			if (abs(nums[i] - nums[i + 1]) > max)
			{
				max = abs(nums[i] - nums[i + 1]);
			}
		}
		return max;
	}
};

线性时间复杂度和空间复杂度:基数排序

觉得自己和失忆了一样,明明才学了没多久

巨慢

class Solution
{
public:
	//获取最大值得位数
	int  GetFigur(vector<int>& arr, int len)
	{
		if (len < 1)
			return -1;
		int max = arr[0];
		for (int i = 1; i < len; i++)
		{
			max = max > arr[i] ? max : arr[i];
		}

		int count = 0;
		while (max != 0)
		{
			max /= 10;
			count++;
		}
		return count;
	}

	//获取十进制整数右数第figur位的数字,figur从0开始
	//例如(123,0)->3   (123,1)->2   (123,2)->1   (123,3)->0
	int GetNum(int n, int figur)
	{
		for (int i = 0; i < figur; i++)
		{
			n /= 10;
		}
		return n % 10;
	}

	//基数排序
	vector<int>RadixSort(vector<int>& arr, int len)//时间复杂度O(d*n),空间O(n),稳定
	{
		queue<int>queArr[10];
		//得到最大数字的位数,确定进队和出队的趟数
		int count = GetFigur(arr, len);
		int index;
		for (int i = 0; i < count; i++)//处理每个数字从右往左的第i个数
		{
			for (int j = 0; j < len; j++)//遍历数组并入队
			{
				index = GetNum(arr[j], i);
				queArr[index].push(arr[j]);//将数字放入对应的队列
			}
			//依次出队
			int j = 0;
			for (int k = 0; k < 10; k++)
			{
				while (!queArr[k].empty())
				{
					arr[j++] = queArr[k].front();
					queArr[k].pop();
				}
			}
		}
		return arr;
	}
	int maximumGap(vector<int>& nums)
	{
		if (nums.size() < 2)
			return 0;
		RadixSort(nums, nums.size());
		int max = INT_MIN;
		for (int i = 0; i < nums.size() - 1; i++)
		{
			if (abs(nums[i] - nums[i + 1]) > max)
			{
				max = abs(nums[i] - nums[i + 1]);
			}
		}
		return max;
	}
};

905. 按奇偶排序数组

905. 按奇偶排序数组

给定一个非负整数数组 A,返回一个数组,在该数组中, A 的所有偶数元素之后跟着所有奇数元素。

你可以返回满足此条件的任何数组作为答案。

示例:

输入:[3,1,2,4]
输出:[2,4,3,1]
输出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也会被接受。

双指针

class Solution
{
public:
	void Swap(int& a, int& b)
	{
		int tmp = a;
		a = b;
		b = tmp;
	}
	vector<int> sortArrayByParity(vector<int>& nums)
	{
		int left = 0;
		int right = nums.size() - 1;
		while (left < right)
		{
			while (nums[left] % 2 == 0)
			{
				if (++left >= nums.size())
					break;
			}
			while (nums[right] % 2 == 1)
			{
				if (--right < 0)
					break;
			}
			if (left >= nums.size() || right < 0)
				break;
			if(left<right)
				Swap(nums[left], nums[right]);

			left++;
			right--;
		}
		return nums;
	}
};

539. 最小时间差

539. 最小时间差

给定一个 24 小时制(小时:分钟 “HH:MM”)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。

示例 1:

输入:timePoints = [“23:59”,“00:00”]
输出:1

化为分钟+排序

注意点:时间要看做两天来计算

class Solution
{
public:
	int findMinDifference(vector<string>& timePoints)
	{
		vector<int>arr;
		int h;
		int m;
		for (auto n : timePoints)
		{
			h = 0;
			m = 0;
			for (int i = 0; i < 5; i++)
			{
				if (i < 2)
				{
					h = h * 10 + n[i] - '0';
				}
				else if (i > 2)
				{
					m = m * 10 + n[i] - '0';
				}
			}
			arr.push_back(h * 60 + m);
			if (h < 12)//也可以不要这个h<12,直接看做两天即可,一天24小时,<12是把前12小时再算一遍
			{
				arr.push_back((h+24) * 60 + m);
			}
		}
		sort(arr.begin(), arr.end());
		int min = INT_MAX;
		for (int i = 0; i < arr.size() - 1; i++)
		{
			if (arr[i] == arr[i + 1])
			{
				return 0;
			}
			if (min > abs(arr[i] - arr[i + 1]))
			{
				min = abs(arr[i] - arr[i + 1]);
			}
		}
		return min;
	}
};

976. 三角形的最大周长

976. 三角形的最大周长

给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的、面积不为零的三角形的最大周长。

如果不能形成任何面积不为零的三角形,返回 0

示例 1:

输入:[2,1,2]
输出:5

3个for循环 超时

class Solution 
{
public:
    int largestPerimeter(vector<int>& nums) 
    {
        int max = INT_MIN;
        sort(nums.begin(), nums.end());
        for (int i = 0; i <nums.size()-2; i++)
        {
            for (int j = i + 1; j < nums.size() - 1; j++)
            {
                for (int k = j + 1; k < nums.size() ; k++)
                {
                    if (nums[i] + nums[j] > nums[k]&&nums[i]+nums[j]+nums[k]>max)
                    {
                        max = nums[i] + nums[j] + nums[k];
                    }
                }
            }
        }
        return max == INT_MIN ? 0 : max;
    }
};

上述代码改为从后往前遍历

class Solution
{
public:
	int largestPerimeter(vector<int>& nums)
	{
		sort(nums.begin(), nums.end());
		for (int i = nums.size() - 1; i >= 2; i--)
		{
			for (int j = i - 1; j >= 1; j--)
			{
				for (int k = j - 1; k >= 0; k--)
				{
					if (nums[j] + nums[k] > nums[i])
					{
						return nums[i] + nums[j] + nums[k];
					}
					else
						break;
				}
			}
		}
		return 0;
	}
};

去看了题解

说实话,内心还是有点隐隐的不认同

我们一定是选「小于 c 的最大的两个数」

class Solution
{
public:
	int largestPerimeter(vector<int>& nums)
	{
		sort(nums.begin(), nums.end());
		for (int i = nums.size() - 1; i >= 2; i--)
		{
			if (nums[i] < nums[i - 1] + nums[i - 2])
				return nums[i] + nums[i - 1] + nums[i - 2];
		}
		return 0;
	}
};

881. 救生艇

881. 救生艇

i 个人的体重为 people[i],每艘船可以承载的最大重量为 limit

每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit

返回载到每一个人所需的最小船数。(保证每个人都能被船载)。

示例 1:

输入:people = [1,2], limit = 3
输出:1
解释:1 艘船载 (1, 2)

排序

因为最多只能坐两人 且 两人重量之和最多为limit

所以设置left和right,如果未上船的最重+最轻>limit,那么就最重的上船走;否则,两人一起上船

class Solution 
{
public:
    int numRescueBoats(vector<int>& people, int limit) 
    {
        sort(people.begin(), people.end());
        int left = 0;
        int right = people.size() - 1;
        int num = 0;
        while (left <= right)
        {
            if (people[left] + people[right] > limit)
            {
                right--;
            }
            else
            {
                left++;
                right--;
            }
            num++;
        }
        return num;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值