Spring Festival Titles (4)

leetcode 198 Robbery

insert image description here

insert image description here

//打家劫舍
class Solution
{
    
    
public:
	int rob(vector<int>& nums)
	{
    
    
		if (nums.size() == 0)return 0;
		if (nums.size() == 1)return nums[0];//只有一间房子
		vector<int>dp(nums.size());
		dp[0] = nums[0];
		dp[1] = max(nums[0], nums[1]);//有两间房子
		for (int i = 2; i < nums.size(); i++) //大于两间房子的情况
		{
    
    
			dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
		}
		return dp[nums.size() - 1];
	}
};

leetcode 414 The third largest number

Use set这个数据结构to achieve:

//小顶堆实现 堆顶元素是最小的元素 
class Solution
{
    
    
public:
		int findK(vector<int>& nums)
		{
    
    
			priority_queue<int, vector<int>, greater<int>>q;//小顶堆实现
			for (int i = 0; i < nums.size(); i++)
			{
    
    
				if (i < 3)
				{
    
    
					q.push(nums[i]);
				}
				else if (nums[i] > q.top()) //在队列里面维护三个较大的元素 这个三个元素自动排序 最大的元素在队首
				{
    
    
					q.pop();
					q.push(nums[i]);
				}
			}
			return q.top();
		}
};

//返回数组中第三大的数字
class Solution
{
    
    
public:
	int thirdMax(vector<int>& nums)
	{
    
    
		set<int>s;//set中的数字自动排序 从大到小排序
		for (int num : nums)
		{
    
    
			s.insert(num);
			if (s.size() > 3)
			{
    
    
				s.erase(s.begin());
			}
		}
		return s.size() == 3 ? *s.begin() : *s.rbegin();//返回集合头元素或尾元素
	}
};

leecode 134 gas station

When you can go around the loop, return the number of the starting gas station; there are gas stations
on a loop , and the gas station has gasoline liters; you have a car with unlimited fuel tank capacity, and you need to consume its gas station to drive from the gas station to the gas station. Gasoline liters, you start from one of the gas stations, the tank is empty at the beginning; given , if you , otherwise return -1, if there is a solution, it is guaranteed to be unique. ( Every time you arrive at a station, you can get the oil of this station, and after you take it, there will be no more, and the oil of each station only exists once )n个第i个gas[i]
第i个第i+1个cost[i]
两个整数数组gas和cost可以绕环路一周(返回最初出发点的时候,油箱里的油量>=0),则返回出发时加油站的编号

insert image description here

For example:
Input: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
Output: 3
Explanation:
Starting from No. 3 gas station (index 3), you can get 4 liters of gasoline. At this time, the fuel tank has = 0 + 4 = 4 liters of gasoline
. Go to No. 4 gas station. At this time, the fuel tank has 4 - 1 + 5 = 8 liters of gasoline.
Go to No. 0 gas station, at this time, the fuel tank has 8 - 2 + 1 = 7 liters of gasoline Go
to No. 1 gas station, at this time the fuel tank has 7 - 3 + 2 = 6 liters of gasoline
Go to No. 2 gas station, at this time the fuel tank has 6 - 4 + 3 = 5 liters of gasoline
Go to No. 3 gas station, you It takes 5 liters of petrol, just enough to get you back to gas station #3.
Therefore, 3 can be the starting index.

小注:
1) If 总油量gas之和减去总消耗cost之和大于等于0, then it must be able to complete a lap, indicating that the sum of the gas station rest[i] at each station must be greater than or equal to 0; 2) 3) i
of each gas station 剩余量rest[i]=gas[i]-cost[i]
starts from 0 and accumulates rest [i], 和记为cursum, 一旦cursum小于0,说明[0,i]区间都不能作为起始位置,起始位置从i+1开始算起,再从0计算cursum;

As shown in the figure below :
insert image description here
C++ implementation :

//贪心算法
class Solution
{
    
    
public:
	int canCompleteCircuit(vector<int>& gas, vector<int>& cost)
	{
    
    
		int cursum = 0;//记录当前遍历到的所有的加油站的剩余油量之和
		int totalsum = 0;//记录一圈下来的剩余油量
		int start = 0;//记录出发位置的下标
		for (int i = 0; i < gas.size(); i++) //这个循环逻辑是在假设可以走完一圈的前提下进行的
		{
    
    
			cursum += gas[i] - cost[i];//记 rest[i]=gas[i]-cost[i]
			totalsum += gas[i] - cost[i];
			if (cursum < 0)
			{
    
    
				start = i + 1;//不断的更新起始下标start;i之前的任意一个位置都不能作为起点
				cursum = 0;//重置为0
			}
		}
		if (totalsum < 0)return -1;//所有站点的剩余油量之和为负 说明肯定是不能回到原点的
		return start;//返回出发位置的索引下标
	}
};


leetcode 300 longest increasing subsequence

The sequence must be 严格递增的,可以不连续;

//动态数组的含义
//dp[i]为考虑前i个元素 以第i个数字结尾的最长递增子序列的长度,nums[i]必须被选取
//dp[j]是(0,i-1)中递增子序列的最大值,dp[i]可由dp[j]的状态递推而来;
//dp[j]是以第i个数字结尾的最长递增子序列的长度;
class Solution
{
    
    
public:
	int lengthOfLIS(vector<int>& nums)
	{
    
    
		if (nums.size() <= 1)return nums.size();
		vector<int>dp(nums.size(), 1);//初始化为1 因为最长连续的子序列至少是1 
		int res = 0;//用于返回一个最长的子序列
		for (int i = 1; i < nums.size(); i++)
		{
    
    
			for (int j = 0; j < i; j++)
			{
    
    
				if (nums[i] > nums[j])//遇到可以递增的序列元素
				{
    
    
					dp[i] = max(dp[i], dp[j] + 1); //取二者中的最大值;dp[i] dp[j]初始都是1
				}
				if (dp[i] > res)res = dp[i];//更新最长的子序列;左值是返回值
			}
		}
		return res;
	}
};

int main()
{
    
    
	vector<int>nums = {
    
     1,2,3,3,2,1,3,2,4,5,3,2,1 };
	Solution so;
	int ans = 0;
	ans = so.lengthOfLIS(nums);
	cout << "最长递增子序列的长度为:" << ans << endl;
	system("pause");
	return 0;
}

leetcode 128 longest continuous subsequence & sword finger offer II

Topic requirements :
Given a 未排序的数组nums, find the longest contiguous subsequence in the array

For example
input: nums=[100,4,200,1,3,2]
output: 4 this 最长的连续子序列是 [1,2,3,4]its length is 4

Input: [0,3,7,2,5,8,4,6,0,1]
Output: 9这个连续子序列是[0,1,2,3,4,5,6,7,8]

C++ implementation:

//会用到哈希集合去重 因为对于所找的最长的子序列 重复元素和非重复的效果是一样的。
//最长连续序列
class Solution
{
    
    
public:
	int longestConsecutive(vector<int>& nums)
	{
    
    
		unordered_set<int>set;//创建一个无序集合 unordered_set 去重 不含重复元素;
		for (const int& num : nums) //num是对象的引用,避免了拷贝 效率更高一些
		{
    
    
			set.insert(num);//将数组中所有的元素都加入到集合中
		}
		int longestStreak = 0;//初始化一个表示最长子序列的变量
		for (const int& num : set)//用范围for循环的方式来遍历集合
		{
    
    
			if (!set.count(num - 1))//比num小1的元素在集合中是不存在的 保证最长序列的长度是从最小的值开始相加的,而不会从一个较大值开始叠加
			{
    
    
				int currentNum = num;
				int currentStreak = 1;//当前连续序列的长度 是会一直更新的
				while (set.count(currentNum + 1))//比当前值大1的元素在集合中存在 说明可以找得到连续的序列了 
					                                             //比如在这里找到1之后 就会一直连续的找到1 2 3 4
				{
    
    
					currentNum += 1;//数值加一
					currentStreak += 1;//表示当前最长序列的长度加一
				}
				longestStreak = max(longestStreak, currentStreak);//维护一个最长的连续子序列
			}
		}
		return longestStreak;
	}
};


leetcode 34 Find the position of the first and last occurrence of the target element in the array

Given a basis 升序排列的整数数组nums和一个目标值target; please find out the start position and end position of the given target value in the array; if the target value does not exist in the array, return [-1,-1].

Two 二分查找implementations:
insert image description here

class Solution {
    
    
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
    
    
        vector<int>res(2,-1);//初始化一个容器 元素初始化为-1
        if(nums.empty())return res;
        int n=nums.size(),l=0,r=n-1;//左右边界
        while(l<r)//二分查找  第一次查找时左右指针的范围是整个数组
        {
    
    
            int m=l+(r-l)/2;
            if(nums[m]>=target)r=m;//更新右边界
            else l=m+1;//更新左边界
        }
        if(nums[l]!=target)return res;//说明不存在目标元素
        res[0]=l;//左边界元素就是我们要找的元素第一次出现的位置
        r=n;//右边界r的位置可能发生变动 因此要重新设置一下右边界 防止溢出
        while(l<r) //二分查找 从左向右查找 第二次查找时左右指针的范围从目标元素第一次出现的位置向右到数组尾部
        {
    
    
            int  m=l+(r-l)/2;
            if(nums[m]<=target)l=m+1;//更新左边界
            else r=m;//更新右边界
        }
        res[1]=l-1;
        return res;
    }
};


Leetcode 77 Composition – BacktrackingM

Given 两个整数n和k, return 1.....nall possible combinations of k numbers; the returned combination cannot contain repeated elements ;
for example:
input: n = 4, k = 2
output:
[
[2,4],
[3,4],
[2,3 ],
[1,2],
[1,3],
[1,4],
]

The idea of ​​the backtracking algorithm :
insert image description here
here is the need to set the variable startIndex, 这个参数用来记录本层递归中,集合从哪里开始遍历; (similar to looking for the ones starting with 1 first in the permutation and combination, and then looking for the ones starting with 2 and then looking down...)
Because each time the element is selected from the collection, 可选择的范围随着选择的进行而收缩, To adjust the selectable range is to rely on startIndex;
Yes; 理解为以1开头的数字 以2开头的数字 以3开头的数字 以4开头的数字; The optional range of numbers in these four cases is different;

Backtracking implementation :


//77 组合
class Solution
{
    
    
private:
	vector<vector<int>>res;
	vector<int>path;

	void backtracking(int n, int k, int startIndex)
	{
    
    
		if (path.size() == k)
		{
    
    
			res.push_back(path);
			return;
		}
		for (int i = startIndex; i <= n; i++) //以1 开头的数字 以2开头的数字 ...这几种情况的遍历起始位置是不一样的,startIndex就是来控制这个起始位置的;
		{
    
    
			path.push_back(i);
			backtracking(n, k, i + 1);
			path.pop_back();//回溯 撤销对节点的处理
		}
	}
public:
	vector<vector<int>>combine(int n, int k)
	{
    
    
		res.clear();
		path.clear();
		backtracking(n, k, 1);//集合下标是从1开始计算的 因为题目指定的是从1到n的元素中选取;
		return res;
	}

};

leetcode 39 combined sum M- backtracking

Given one 无重复元素 的整数数组 candidates 和一个目标整数 target, find all the different combinations of numbers in candidates that can make the number sum target, and return it as a list. You can return these combinations in any order. 返回的每个组合中是可以包含重复数字的;
The same number in candidates can be selected repeatedly without limit. Two combinations are different if the chosen number of at least one number is different.

For example:
input: candidates = [2,3,6,7], target = 7
output: [[2,2,3],[7]]
explanation:
2 and 3 can form a set of candidates, 2 + 2 + 3 = 7. Note 2 can be used multiple times.
7 is also a candidate, 7 = 7 .
There are only these two combinations.
insert image description here
It is used in this question startIndex来控制for循环的起始位置, if 是一个集合来求组合的话就需要用到startindex;
why do we have this startIndex?
Every time an element is selected from the collection, 可选择的范围随着选择的进行而收缩, to adjust the selectable range, is to rely on startIndex;

//candidades中的数字是可以多次重复选取的,每个组合中可以包含重复的数字
class Solution
{
    
    
private:
	vector<vector<int>>res;//存放最终的结果
	vector<int>path;//存放单条路径
	void backtracking(vector<int>& candidates, int target, int sum, int startIndex)//startIndex用来控制for循环的起始位置;
	{
    
    
		if (sum > target)return;//递归终止
		if (sum == target)
		{
    
    
			res.push_back(path);
			return;
		}
		for (int i = startIndex; i < candidates.size(); i++)//startindex用来控制一次只能选取一个数字,但是下次还是可以选取和上次一样的数字的;
		{
    
    
			sum += candidates[i];//处理当前节点
			path.push_back(candidates[i]);
			backtracking(candidates, target, sum, i);//因为是可重复的 下一次的递归还是可以从头开始遍历 所以是i 不是i+1
			sum -= candidates[i];//开始向上回溯
			path.pop_back();
		}
	}
public:
	vector<vector<int>>combinationSum(vector<int>& candidates, int target)
	{
    
    
		res.clear();
		res.clear();
		backtracking(candidates, target, 0, 0);
		return res;
	}
};


leetcode 40 Combined sum II

Given a candidate number 集合 candidates 和一个目标数 target, find all combinations in candidates that can make the sum of the numbers into target.

in candidates每个数字在每个组合中只能使用一次

For example:
input: candidates = [10,1,2,7,6,1,5], target = 8,
output:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

Small note:
The title requires:
组合中有重复元素,但是不能有重复的组合 ;
Therefore, in the process of searching, it is necessary to remove the repeated combination.
Understanding deduplication : So what we want to repeat is the "used" on the same tree layer, 同一树枝上的都是一个组合里的元素,不用去重.
At the same time, if the tree layer is deduplicated, the array needs to be sorted ;
the so-called 去重是不能以相同的元素开头;

insert image description here


class Solution3
{
    
    
private:
	vector<vector<int>>res;
	vector<int>path;
	void backtracking(vector<int>&candidates,int target,int sum,int startIndex,vector<bool>&used)
	{
    
    
		if(sum>target)return;//剪枝操作
		if (sum == target)
		{
    
    
			res.push_back(path);
			return;
		}
		for (int i = startIndex; i < candidates.size(); i++)
		{
    
    
			if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false)continue;//同一层上去重操作 如果是同一树枝上 是used[i-1]=true;
			sum += candidates[i];
			path.push_back(candidates[i]);
			used[i] = true;
			backtracking(candidates, target, sum, i + 1, used);//数组中的数字是不能重复选取的
			path.pop_back();
			sum -= candidates[i];
			used[i] = false;
		}
	}
public:
	vector<vector<int>>combine(vector<int>& candidates, int target)
	{
    
    
		vector<bool>used(candidates.size(), false);
		sort(candidates.begin(), candidates.end());//因为涉及去重的问题 所以去重之前先排序
		backtracking(candidates, target, 0, 0, used);
		return res;
	}
};

leetcode 62 different paths

A robot is located in m x nthe upper left corner of a grid (the starting point is labeled "Start" in the figure below).
robot 每次只能向下或者向右移动一步. The robot tries to reach the bottom right corner of the grid (marked "Finish" in the image below).
How many different paths are there in total?
insert image description here
input: m = 3, n = 7
output:28

Use dp(i,j)表示从左上角走到(i,j)位置的路径数量, where the ranges of i and j are [0,m) [0,n);
Since we can only move one step down or to the right ( 每一格的路径是由其左一格和上一格决定的), if we want to go to (i,j) If you take a step down, you will come from (i-1, j); if you take a step to the right, you will come from (i, j-1); you can write the dynamic programming equation:
dp(i,j)=dp(i−1,j)+dp(i,j−1);

It should be noted that if i=0, then dp(i−1,j) is not a state that meets the requirements, we need to ignore this item; similarly, if j=0, then dp(i,j−1 ) is not a satisfactory state, we need to ignore this item.

The initial condition is dp(0,0), ie 从左上角走到左上角有一种方法.

The final answer is dp(m−1,n−1).
for 第一行dp[0][j] 或者第一列dp[i][0] 由于都是在边界上的点, 所以只能为1,即从左上角到dp[0][j] 或到dp[i][0]都是只有一种路径可以走;

insert image description here

class Solution
{
    
    
public:
	int uniquePaths(int m, int n) //m行n列
	{
    
    
		vector<vector<int>>dp(m, vector<int>(n));//初始化一个m行n列初始值都为0的二维数组,用于存放求得的路径值
		for (int i = 0; i < m; i++) //遍历行 忽略 j=0 的情况
		{
    
    
			dp[i][0] = 1;//
		}
		for (int j = 0; j < n; j++) //遍历列 忽略 i=0 的情况
		{
    
    
			dp[0][j] = 1;
		}
		for (int i = 1; i < m; i++)//i=0 j=0的情况在上面已经考虑到了 因此这里i j 都从1开始遍历
		{
    
    
			for (int j = 1; j < n; j++)
			{
    
    
				dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
			}
		}
		return dp[m - 1][n - 1];
	}
};



leetcode 63 different paths II

A robot is located in m x nthe upper left corner of a grid (the starting point is labeled "Start" in the figure below).
robot every time 只能向下或者向右移动一步. The robot tries to reach the bottom right corner of the grid (marked "Finish" in the image below).
Now consider the grid 有障碍物. So how many different paths will there be from top left to bottom right?
Obstacles and empty positions in the grid are represented by 1 and 0, respectively.

Example:
Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is an obstacle in the middle of the 3x3 grid.
There are 2 different paths from the upper left corner to the lower right corner:

  1. Right -> Right -> Down -> Down
  2. Down -> Down -> Right -> Right

insert image description here

Code:

//动态数组dp[i][j]的含义是到达当前位置(i,j)的路径数目
class Solution
{
    
    
public:
	int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)//输入是一个二维数组
	{
    
    
		int m = obstacleGrid.size();//行
		int n = obstacleGrid[0].size();//列
		vector<vector<int>>dp(m, vector<int>(n, 0));//初始化一个m行n列的二维数组
		for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++)//一直向下走第一列并且第一列中没有障碍物
		{
    
                        //对于只走第一列且第一列中有障碍物的额情况是不用考虑的,此时是没有路径的;
			dp[i][0] == 1;//只有一条路径情况
		}
		for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++)//一直向右走第一行并且第一行没有障碍物
		{
    
    
			dp[0][j] == 1;
		}
		for (int i = 1; i < m; i++)
		{
    
    
			for (int j = 1; j < n; j++)
			{
    
    
				if (obstacleGrid[i][j] == 1)continue;
				dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
			}
		}
		return dp[m - 1][n - 1];
	}
};

leetcode 287 Find repeating numbers M

Given an array nums, assuming 这个数组中只存在一个重复的数字, please return this repeated number;
use one 哈希表to realize the statistics of the number of occurrences of the array;
code implementation :

class Solution {
    
    
public:
    int findDuplicate(vector<int>& nums) 
    {
    
    
        unordered_map<int,int>table;
        for(auto num:nums)
        {
    
    
            table[num]++;
        }
        int res=0;
        for(auto p:table)
        {
    
    
            if((p.second)>1)
            {
    
    
                return res=p.first;
            }
        }
        return res;
    }
};

leetcode 135 Hand out candy H

nchildren stand in a row. Here you go 整数数组 ratings 表示每个孩子的评分.
You need to distribute candy to these children according to the following requirements:

每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。

Please distribute candy to each child, count and return what needs to be prepared 最少糖果数目.

For example:
input: ratings = [1,0,2]
output: 5
explain:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果

贪心算法实现------- The overall idea is divided 从左向右遍历into 从右向左遍历two big steps;
traversal from left to right:
local optimal : as long as the score on the right is higher than that on the left, the child on the right will have one more candy;
global optimal : adjacent Among the children, the right child with a high score gets more candies than the left child;
if ratings[i] > ratings[i - 1]then [i] must have one more candy than [i - 1], so greedy:candyVec[i] = candyVec[i - 1] + 1

Traversing from right to left
If ratings[i] > ratings[i + 1], at this time, candyVec[i] (the number of candies of the i-th child) is available 有两个选择, one is candyVec[i + 1] + 1 (the number of candies obtained by adding 1 to the right), and the other is candyVec[i] (previously compare the number of candies that the right child is greater than the left child gets).
Then it's greedy again,
local optimum : 取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量即大于左边的也大于右边的.
Global Optimum : Among adjacent children, children with higher scores get more candies.
Local optimum can lead to global optimum.
So take candyVec[i + 1] + 1 and candyVec[i] the largest number of candies, candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多,也比右边candyVec[i + 1]的糖果多.

As shown in the figure below :
insert image description here
code implementation:


class Solution
{
    
    
public:
	int candy(vector<int>& ratings)
	{
    
    
		vector<int>candyVec(ratings.size(), 1);//初始化一个容器存放最终的结果
		//从前向后遍历
		for (int i = 1; i < ratings.size(); i++)
		{
    
    
			if (ratings[i] > ratings[i - 1])candyVec[i] = candyVec[i - 1] + 1;
		}
		//从后向前遍历
		for (int i = ratings.size() - 2; i >= 0; i--)//i从数组的倒数第二个元素开始计数  配合下面的i+1;
		{
    
    
			if (ratings[i] > ratings[i + 1])
			{
    
    
				candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);
			}
		}
		//统计最后的结果
		int res = 0;
		for (int i = 0; i < candyVec.size(); i++)
		{
    
    
			res += candyVec[i];
		}
		return res;
	}
};


leetcode 26 Remove duplicates in an ordered array I

Give you one 有序数组nums, please delete the repeated elements in place, 使每个元素最多只出现一次and return the length of the deleted array;
for example:
Input: nums = [1,1,2]
Output: 2, nums = [1,2,_]
Explanation: The function should return the new length 2, and the first two elements of the original array nums are modified to 1, 2. Elements beyond the new length in the array do not need to be considered.


The core idea of 每遇到一个不同的元素都将其复制到前面的一个位置,也就是slow指针之前的元素是不存在重复元素的​​the double-pointer solution : ;
Since the given array is ordered, so for 任意i<jIf nums[i]=nums[j]then for 任意i<=k<=jmust have nums[i]=nums[k]=nums[j]equal elements in the array, the subscript must be continuous, using the characteristics of the order of the array, you can use the double pointer The solution is solved;
assuming that the length of the array nums is n, 快指针fast依次遍历从1到n-1的每个位置for each position, if nums[fast] is not equal to nums[fast-1], 说明nums[fast]和之前的元素都不相同,因此将nums[fast]的值复制到nums[slow]then add one to the value of slow to point to the next position;
after the traversal, 从nums[0]到nums[slow-1]的每个元素都不相同且包含原数组中的每个不同的元素, so the new length is slow, just return slow;

class Solution {
    
    
public:
    int removeDuplicates(vector<int>& nums) {
    
    
        int n = nums.size();
        if (n == 0)  return 0;
        int fast = 1, slow = 1;//初始化快慢指针
        while (fast < n) 
        {
    
    
            if (nums[fast] != nums[fast - 1]) //当快指针指向的当前元素和前一个元素不等时,开始用快指针指向的元素对慢指针指向的元素进行覆盖
            {
    
    
                nums[slow] = nums[fast];//用元素覆盖的方式实现去重
                ++slow;
            }
            ++fast;//当快慢指针指向相同的元素时,快指针持续前进
        }
        return slow;//最终慢指针指向的元素的 位置下标就是去重后的数组的长度;
    }
};

insert image description here


//删除有序数组中的重复元素 使每个元素最多只出现一次
class Solution
{
    
    
public:
	int removeDuplicates(vector<int>& nums)
	{
    
    
		int n = nums.size();
		for (int i = 1; i < n; i++)//从数组的第二个元素开始遍历
		{
    
    
			if (nums[i] == nums[i - 1])
			{
    
    
				nums.erase(nums.begin() + i);//删除重复元素的第二个
				i--;//下一次的遍历从重复元素的第一个开始遍历
				n--;//删除了一个重复数字之后,数组总的长度减一;
			}
		}
		return nums.size();
	}
};


//如果是返回去重之后的数组

class Solution
{
    
    
public:
	vector<int>removeDuplicates(vector<int>& nums)
	{
    
    
		vector<int>ans;
		int n = nums.size();
		for (int i = 1; i < n; i++)
		{
    
    
			if (nums[i] == nums[i - 1])
			{
    
    
				nums.erase(nums.begin() + i);
				i--;
				n--;
			}
		}
		for (int i = 0; i < nums.size(); i++)
		{
    
    
			ans.push_back(nums[i]);
		}
		return ans;
	}
};

int main()
{
    
    
	vector<int>nums = {
    
     1,2,3,3,3,5,6,5 };
	Solution so;
	vector<int>res;
	res = so.removeDuplicates(nums);
	for (auto it = res.begin(); it != res.end(); it++)
	{
    
    
		cout << "去重之后的数组是:" << *it << endl;
	}

	system("pause");
	return 0;
}

leetcode 80 [Delete duplicates in an ordered array II]

Give you one 有序数组nums, please delete the repeated elements in place, 使每个元素最多只出现两次, and return the length of the deleted array;

For example:
Input: nums = [1,1,1,2,2,3]
Output: 5, nums = [1,1,2,2,3]
Explanation: The function should return the new length length = 5, and the first five elements of the original array are modified to 1, 1, 2, 2, 3. Elements beyond the new length in the array do not need to be considered.

Code:

//这种类型题的通解做法
//原地删除有序数组中的重复项 使每个数字只出现k次 
//由于是保留 k 个相同数字,对于前 k 个数字,我们可以直接保留
//对于后面的任意数字,能够保留的前提是:与当前写入的位置前面的第 k 个元素进行比较,不相同则保留
//我们令 k = 2,假设有如下样例
//当len<k时直接保留即可;当len>k后 看nums[len-k]是否等于num 不等才保留;
//
//[1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3]
//
//首先我们先让前 2 位直接保留,得到 1, 1
//对后面的每一位进行继续遍历,能够保留的前提是与当前位置的前面 k 个元素不同(答案中的第一个 1)
//因此我们会跳过剩余的 1,将第一个 2 追加,得到 1, 1, 2
//继续这个过程,这时候是和答案中的第 2 个 1 进行对比,因此可以得到 1, 1, 2, 2

class Solution
{
    
    
public:
	int removeDuplicate(vector<int>& nums)
	{
    
    
		return work(nums, 2);
	}
	int work(vector<int>& nums, int k)
	{
    
    
		int len = 0;
		for (auto num : nums)
		{
    
          //len<k时 直接保留;len>k时 比较nums[len-k]和当前num是否相等 不等才进行保留;
			if (len < k || nums[len - k] != num)//对于前k个数字不论是否重复 直接保留即可;
			{
    
    
				nums[len++] = num;//当前值符合保留的条件 对当前遍历到的数值进行保留
			}
		}
		return len;
	}
};

leetcode 316 [Remove the repeated letter M]

Given one 字符串 s, please remove the repeated letters in the string so that each letter appears only once. It is necessary to ensure that the result is returned 字典序最小(it is required that the relative positions of other characters cannot be disturbed).
For example:
input: s = "bcabc"
output: "abc"
input: s = "cbacdcbc"
output: "acdb"

Code:

// 之所以用这种方法求解是因为要保持字典序最小;
// 从a到z对应ascii码值是递增的;
class Solution {
    
    
public:
	string removeDuplicateLetters(string s) 
	{
    
    
		vector<int> Hashtable(128, 0);//数组作哈希表 比单纯的哈希表要快
		vector<bool> flag(128, false);//判断这个值是否已经“定下来了”,假如定下来了,那扫到的时候直接跳,当没看见就完事了
		for (char x : s) Hashtable[x]++;//记录下次数
		string ans = "0";//为什么要预先放个零呢?充当guard,省的判空那么麻烦了,后面的肯定比零大,因为都是字母,返回的时候从1开始返回
		for (char x : s) 
		{
    
    
			Hashtable[x]--;//每遍历到一个元素 就递减其出现次数
			if (flag[x]) continue;//元素已经被确定了 跳过重复的元素;    //当前元素比尾部元素大,就一直在尾部添加元素;当前元素比尾部元素小 就一直删除尾部元素 维持尾部的元素是一个最小元素
			while (x < ans.back() && Hashtable[ans.back()]) //以bcabc为例 对于b 我们要的b是a之后的b 我们要的c是a之后的c 这样才可以保证字典序的顺序; 
			{
    
                                     //删除元素就是没使用这个元素 将其标记为false
				flag[ans.back()] = false;//对于bcabc当遍历到a后,因为a<b a<c就会依次删除尾部的元素c b
				ans.pop_back();//删除这个元素的同时要判断这个元素在后面还是会出现的,保证这个元素在新的字符串中只出现一次;
			}
			ans += x;
			flag[x] = true;//在新的字符串中确定了一个元素
		}
		return ans.substr(1);//获取字符串ans中从第一位开始到最后一位的字符串;第0位是"0"不获取
	}
};



removes all adjacent duplicates in a string

Given a string S consisting of lowercase letters , 重复项删除操作会选择两个相邻且相同的字母, and deletes them.
Repeat the deduplication operation on S until no further deduplication is possible.

Input: "abbaca"
Output: "ca"
Explanation:
For example, in "abbaca", we can delete "bb" Since the two letters are adjacent and identical, this is the only duplicate that can be deleted at this time. Then we get the string "aaca", again only "aa" can be deduplicated, so the final string is "ca".

Code:

class Solution {
    
    
public:
    string removeDuplicates(string S) 
    {
    
    
        stack<char>st;
        for(char s:S)
        {
    
    
            if(st.empty()||s!=st.top())//有两种情况会入栈 一种是一开始栈为空时,另一种是当前元素和栈顶元素不等的时候;
            {
    
    
                st.push(s);
            }
            else
            {
    
    
                st.pop();
            }
        }
        string res="";
        while(!st.empty())
        {
    
    
            res+=st.top();
            st.pop();
        }
        reverse(res.begin(),res.end());
        return res;
    }
};

//用1209的方法求解即可 k==2
class Solution {
    
    
public:
    string removeDuplicates(string s) {
    
    
        vector<pair<char,int>>res;
        for(auto&i:s)
        {
    
    
            if(!res.empty()&&res.back().first==i)
            {
    
    
                if(++res.back().second==2)
                {
    
    
                    res.pop_back();
                }
            }
            else
            {
    
    
                res.push_back(make_pair(i,1));
            }
        }
        string ans;
        for(auto&s:res)
        {
    
    
            int n=s.second;
            while(n--)
            {
    
    
                ans+=s.first;
            }
        }
        return ans;
    }
};

leetcode 1209 Delete adjacent repeated elements in a string II (delete k adjacent repeated elements)

The title is 删除字符串中相邻的k个字符串to return the deleted string;
repeat the operation on the string until it cannot continue;

For example:
Input: s = "deeedbbcccbdaa", k = 3
Output: "aa"
Explanation:
First delete "eee" and "ccc" to get "ddbbbdaa"
and then delete "bbb" to get "dddaa" and
finally delete "ddd" to get "aa"
insert image description here
For the above example:
yes First store in the container d-1 e-2 (d 出现次数为1, e出现次数为2) when traversing to the third e, because at this time 2+1=3=k just meets the k of the question , and then delete, just delete e-2, that is, to delete the element repeated 3 times the goal of;

小注:
容器中保存的是元素和其出现次数组成的pair数据结构,不是多个相同的元素,对于重复的元素,只存储一个元素和一个表示其出现次数的数值 ;
The k given in the title is 3. Take deleting e as an example. When traversing to the third e, it is found that two e have been traversed before, then 2+1=3 At this time, the element e should be deleted, then The e element will not exist in the container. Every time the same element is traversed, the pair will increment its occurrence count and store it. When the count value reaches k-1, the element will be deleted in the container; because our
data The storage type is pair, then the data mode of the stored e is an e corresponding to a number 3, only delete this

Code:


//删除字符串中连续重复k个的元素
class Solution
{
    
    
public:
	string removeDuplicates(string s, int k)
	{
    
    
		vector<pair<char, int>>res;//vector中存放的元素类型是pair 
		for (auto& i : s)
		{
    
    
			if (!res.empty() && res.back().first == i)//遇到重复元素 并且此时这个元素的出现次数加一正好等于k
			{
    
    
				if (++res.back().second == k)//只有当达到指定的重复次数时 才开始删除元素;没到之前 每遇到重复的元素 就会递增他们的出现次数
				{
    
    
					res.pop_back();
				}
			}
			else
			{
    
    
				res.push_back(make_pair(i, 1));//存入一个pair类型的数据进res中 i是元素 初始化元素的出现次数为1 ;如果遇到的是相同的元素 递增第二个参数,增加他们的出现次数
			}
		}
		string ans;//拼接返回最后的结果
		for (auto& i : res)
		{
    
    
			int n = i.second;//n是几个单词 表示其出现次数
			while (n--)
			{
    
    
				ans += i.first;//拼接几个重复的单词即可
			}
		}
		return ans;
	}
};

Guess you like

Origin blog.csdn.net/weixin_48433164/article/details/123546119