堆,队列,递归(笔记+刷题)

//C++
//其实栈就这几个成员函数
empty() //堆栈为空则返回真 
pop() //移除栈顶元素 
push() //在栈顶增加元素 
size() //返回栈中元素数目 
top() //返回栈顶元素 

#include<iostream>//c++标准头文件,可以使用cout,cin等标准库函数 
#include<stack>//使用stack时需要的头文件 
using namespace std;//命名空间,防止重名给程序带来各种隐患,使用cin,cout,stack,map,set,vector,queue时都要使用
int main() {
	stack<int> s;//定义一个int类型的stack

	s.push(1);//往栈里放入一个元素1
	s.push(2);//往栈里放入一个元素2
	s.push(3); //往栈里放入一个元素3

	cout << "按顺序放入元素1、2、3后,目前栈里的元素:1 2 3" << endl;																		  
	cout << "s.size()=" << s.size() << endl;//s.size()返回栈内元素的个数																      
	cout << "s.empty()=" << s.empty() << endl; //判断栈是否为空,值为1代表空,0代表非空,用s.size()同样可以判断 ,s.size()的值为0就代表空的    
	cout << "s.top()=" << s.top() << endl;//查看栈顶的元素																				      
	cout << endl;

	s.pop();//弹出栈顶元素															
	cout << "s.pop()后,目前栈里的元素:1 2" << endl;.		//s.pop()后,目前栈里的元素:1 2
	cout << "s.size()=" << s.size() << endl;				//s.size() = 2				
	cout << "s.empty()=" << s.empty() << endl;				//s.empty() = 0
	cout << "s.top()=" << s.top() << endl;					//s.top() = 2
	cout << endl;


	s.pop();
	cout << "s.pop()后,目前栈里的元素:1" << endl;					//s.pop()后,目前栈里的元素:1
	cout << "s.size()=" << s.size() << endl;						//s.size() = 1
	cout << "s.empty()=" << s.empty() << endl;						//s.empty() = 0
	cout << "s.top()=" << s.top() << endl;							//s.top() = 1
	cout << endl;

	s.pop();
	cout << "s.pop()后,目前的栈是空的" << endl;							//s.pop()后,目前的栈是空的
	cout << "s.size()=" << s.size() << endl;								//s.size() = 0
	cout << "栈是空的就不能用s.top()访问栈顶元素了" << endl;				//栈是空的就不能用s.top()访问栈顶元素了
	cout << "s.empty()=" << s.empty() << endl;								//s.empty() = 1

}


https://blog.csdn.net/2301_76366823/article/details/128876930    vector
https://blog.csdn.net/weixin_52115456/article/details/127595817    stack


//**********************************************************************************************************************************************//
//****************************************************************     栈    *******************************************************************//
//**********************************************************************************************************************************************//
//栈的定义
#define Maxsize 10
typedef struct {
	int data[Maxsize];
	int top;
}SqStack;

//**************************************************************************************************************************************//
//栈的初始化
void InitStack(SaStack &S ) {
	S.top = -1;        //初始化栈顶指针
}

void testStack() {
	SqStack S;
	InitStack(S);
}
//**************************************************************************************************************************************//
//判断栈是否为空
bool StackEmpty(SqStack S) {
	if (S.top == -1)
		return true    //栈空的
	else
		return false;
}
//**************************************************************************************************************************************//
//插入栈顶元素
bool Push(SqStack& S, int x) {     //&意思:直接影响整个S  你加的x,带进去就完了,不用带回。所以不用 &x
	if (S.top == Maxsize - 1)   //栈的最大容量是Maxsize  
		return false;          //第一个元素:S.top==0 ,所以减1
	S.top = S.top + 1;         //S.top先上去        //这两行可以代替:S.data[++S.top]=x   //细节:前自增  你先上去,再赋值
	S.data[S.top] = x;         //然后在这个楼层,加入x的S.data
	return true;
}
//**************************************************************************************************************************************//
//删除栈顶元素
bool Pop(SqStack& S, int& x) {   //这里删除的 x 要带回     //假删除:数据还在,你往下 top ,“假装”数据没了
	if (S.top == -1)                                       //创建的数组不能手动 free
		return false
	x = S.data[S.top];		//核心:先把值给x		 //x=S.data[S.top--]   后自减:先赋值,再自减					
	S.top = S.top - 1;		//然后再自己下去
	return true;
}
//**************************************************************************************************************************************//
//获取栈顶元素
bool GetTop(SqStack S, int& x) {
	if (S.top == -1)           //都没有栈,输出个毛啊
		return false;
	S.data[S.top] = x;
	return true;
}

//有个细节:top 刚开始指向-1 还是0          0的时候,top在上面 ,记住这个就足够了
//这个问题,你就这么想:你要建房子:你从地下室开始建还是从0开始
//  -1 开始:建房子:你先上去,再建房子    拆房子:你先拆(把值传过去)了,再下去     -1是不能建房子,拆房子!必须上去再建房子
//  0开始:建房子:直接建房子,再上去      拆房子:你先下去,再拆(把值传过去)       top指向房子上面(刚开始还买房子时候,就指向房子)
      //  S.data[S.top++]=x  建房子                S.data[--S.top]=x
	  
//**************************************************************************************************************************************//
//共享栈定义
#define Maxsize
typedef struct {
	int data[Maxsize];
	int  top1;
	int  top2;
}ShareStack;

void InitStack(ShareStack& S) {     //数据存储在 [ 0 --- Maxsize-1 ]
	S.top1 = -1;               // S.top1 在-1层   
	S.top2 = Maxsize;          // S.top2 在顶层
}

//**************************************************************************************************************************************//
//判断共享栈是否满了
bool ShareStackEmpty(ShareStack S) {
	if (S.top1 + 1 ==S. top2)
		return true;   //栈满了
	else
		return false;
}
//**************************************************************************************************************************************//
//链栈   //本质就是头插法
typedef  struct Linknode {
	int data;
	struct Linknode* next;
}*LiStack;

//***********************************************************************************************************************************
//****************************************                队列               *******************************************************
//***********************************************************************************************************************************
//队尾插入  对头删除
#define Maxsize 10
typedef struct{
	int data[Maxsize];
int front, rear;                   //front 指向第一个元素(栈;最底下)下面掉(删除)
} SqQueue;                         //rear 后面的后面(上面的上面)和那个 top =0开始一样

void testQueue() {
	SqQueue Q;          //刚开始front rear 指向第一个空位
}

//**************************************************************************************************************************************//
bool SqQueue(SqStack & Q) {
	if (Q.rear ==Q. front)     //队列空
		return true;
	else
		return false;
 }

//**************************************************************************************************************************************//
//入队                              //此时,rear 指向下一个元素
bool EnQueue(SqQueue& Q, int x) {
	if ((Q.rear + 1) % Maxsize == Q.front)    //循环队列,rear 下一个是front 的话,说明满了! 
		return false;                         //此时的rear 浪费了!没办法,为了区分 Q.rear ==Q. front 是空的。所以只能浪费rear 这个空间
	Q.data[Q.rear] = x;                       //rear 指向下一个元素,所以直接赋值
	Q.rear = (Q.rear + 1) % Maxsize;          //赋值完,再+1     //为了达到循环效果,进行了%,让它达到9(满了之后)以后,再回到0,转起来
	return true;                             
} 
//**************************************************************************************************************************************//
//出队								//此时,rear 指向下一个元素
bool DeQueue(SqQueue& Q, int& x) {
	if (Q.rear == Q.front)
		return false;                    //删除元素,判断对空      //插入元素,判断对满(  (Q.rear + 1) % Maxsize == Q.front  )
	x = Q.data[Q.front];
	Q.front = (Q.front + 1) % Maxsize;  //删除对头,头结点上移    //插入队尾,尾结点上移
	return true;
}
//**************************************************************************************************************************************//
//获取对头元素 (删除对头一样,不移就行)
bool GetHead(SqQueue Q, int& x) {
	if (Q.rear == Q.front)
		return false;
	x = Q.data[Q.front];
	return true;
}

//**************************************************************************************************************************************//
//入队								//此时,rear 指向最后元素  (主要区分下一个元素)    (初始状态:-1)
bool EnQueue(SqQueue& Q, int x) {                      //初始状态: rear 指向-1  front 指向 0    (刚开始空的时候,-1暂时住一下,之后,元素不能在-1空间)
	if ((Q.rear + 2) % Maxsize == Q.front)             //满状态:   rear 指向-2  front 指向 0   (浪费-1空间) 
		return false;                         
	Q.data[Q.rear] = x;                       
	Q.rear = (Q.rear + 1) % Maxsize;  
	return true;
}

//**************************************************************************************************************************************//
//出队								//此时,rear 指向最后一个元素         (初始状态:-1)
bool DeQueue(SqQueue& Q, int& x) {
	if (Q.rear + 1 == Q.front)			//初始状态: rear 指向-1  front 指向 0    (刚开始空的时候,-1暂时住一下,之后,元素不能在-1空间)
		return false;
	Q.front = (Q.front + 1) % Maxsize;
	return true;
}

//**************************************************************************************************************************************//
//获取队列的长度
//公式: ( rear+Maxsize - front) % Maxsize = len

//判断队列空/满的三种方法:
//方法一:
//初始状态/空状态: Q.rear==Q.front      满的状态: (Q.rear+1)%Maxsize==Q.front    缺点:浪费 rear 空间(就为了区分空与满的状态)

//方法二:引入size用来计数
//插入元素:size+1   删除元素:size-1
//队列空:Q.rear==Q.front && size==Maxsize (多加一个附加条件)  队列满:Q.rear==Q.front && size==0     特点:通过附加条件来判断
if (Q.rear == Q.front) {                                                                            //  优点:利用率100%
	if (size == Maxsize)
		return 慢;
	else 
		return 空
}

//方法三:引入tag 用来判断操作
//删除操作:tag=0     插入操作:tag=1
// (tag=1)插入操作后:Q.rear==Q.front--->满      (tag=0) 删除操作后:Q.rear==Q.front--->空 
//队列空:Q.rear==Q.front && tag=0            队列满:Q.rear==Q.front && tag=1          不用浪费元素,同样通过附加条件来判断

//**************************************************************************************************************************************//
//队列的定义
typedef struct LinkNode{    //定义了链式队列结点
	int data;
struct LinkNode* next;
}LinkNode;

typedef struct {           //在链式队列的基础上,定义了队列的头尾结点
	LinkNode* front,*rear;
}LinkQueue;

//**************************************************************************************************************************************//
//初始化(带头结点)
void InitQueue(LinkQueue& Q) {
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));    //判断队列空: Q.front==Q.rear   或者   front->next==NULL 都行
	Q.front->next = NULL;
}

void testLinkQueue() {
	LinkQueue Q;
	InitQueue(Q);
}

//*************
//判断是否为空(带头结点)
bool IsEmpty(LinkQueue Q) {
	if ( Q.front == Q.rear ) 
//  if ( Q.front==NULL )
		return true;
	else
		return false;
 }

//**************************************************************************************************************************************//
//初始化(不带头结点)
void InitQueue(LinkQueue& Q) {
	Q.front = NULL;
	Q.rear = NULL;
}

//*************
//判断是否为空(不带头结点)
bool IsEmpty(LinkQueue Q) {
	if (Q.front == NULL)    //核心: Q.front==NULL
		return true;
	else
		return false;
}

//**************************************************************************************************************************************//
//入队(带头结点)
void EnQueue(LinkQueue& Q, int x) {
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;       //插入尾部,所以指向NULL (先右,后左)
	Q.rear->next = s;     //rear尾部指向s
	Q.rear = s;           //rear 移过去
}

//**************************************************************************************************************************************//
//入队(不带头结点)
void EnQueue(LinkQueue& Q, int x) {
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	if (Q.front == NULL) {    //空的话,Q,front==NULL  Q.rear==NULL
		Q.front = s;		  //都指向第一个结点
		Q.rear = s;
	}
	else {
		Q.rear->next = s;
		Q.rear = s;
	}
}

//**************************************************************************************************************************************//
//出队(带头结点)
bool DeQueue(LinkQueue& Q, int& x) {
	if (Q.front == Q.rear)
		return fasle;            //空的话,出个毛啊
	LinkNode* P = Q.front->next;		//后面要free这个结点,所以提前搞个p指向这front (头出)
	x = P->data;
	Q.front->next = P->next;   //跳过p
	if (Q.rear == P)          //出队的是最后一个结点
		Q.rear = Q.front;     //rear 和 front 指向头结点
	free(P);
	return true;
}

//**************************************************************************************************************************************//
//出队(不带头结点)
bool DeQueue(LinkQueue& Q, int& x) {
	if (Q.front == NULL)          //空的话,出个毛啊
		return false;
	LinkNode* p = Q.front;    //后面要free这个结点,所以提前搞个p指向这front (头出)
	x = p->data;
	Q.front = p->next;			//跳过p
	if (Q.rear == p) {         //跳过p之后,发现最后一个指向p,那么这时就变成了空队
		Q.front = NULL;        //不带头结点,初始化,front rear 指向NULL
		Q.rear = NULL;
	}
	free(p);            //别忘了释放p
	return true;
}

//不会出现队列满的情况--->可以无限插入

//**************************************************************************************************************************************//
//**************************************************************************************************************************************//
//栈  括号匹配问题
#define Maxsize 10
typedef struct {
	char data[Maxsize];
	int top;             //栈顶指针
};

bool bracketCheck(char str[], int length) {
	SqStack S;
	InitStack(S);
	for (int i = 0; i < length; i++) {
		if (str[i] == '(' || str[i] == '[' || str[i] == '{') {
			push(S, str[i]);			 //如果是“右括号”,插入栈里
		}
		else {
			if (StackEmpty(S))          //当有个“左括号”,如果空了,那就错误!(没有和他匹配)
				return false;           //但是结束后,空了就是对的。
			char topElem;
			pop(S, topElem);                        //弹出栈顶元素,返回给 topElem
			if (str[i] == ')' && topElem != '(')   //有括号和左括号不匹配,那就是错的
				return false;
			if (str[i] == ']' && topElem != '[')
				return false;
			if (str[i] == '}' && topElem != '{')
				return false;                     //只要弹出的栈顶元素是对的,那就继续循环
		}
	}
	return StackEmpty(S);       //都结束后,栈空,那就完成。如果没空。那就说明有问题。
}

void InitStack(SqStack &S)     //初始化栈
bool StackEmpty(SqStack S)     //判断栈是否为空
bool Push(SqStack &S,char x)   //新元素入栈
bool Pop(SqStack &S,char &x)   //弹出栈顶元素,x返回

//
//前缀表达式(波兰表达式)   中缀表达式   后缀表达式(逆波兰表达式)
//为啥引入前后缀表达式?  因为中缀表达式,人类看的话,能看出来运算顺序。但是,计算机无法确认运算顺序。
//前缀表达式: a+b ---> +ab  运算符号插在前面。+-+abcd 从右往左(+-+)顺序计算--->运算顺序跟a+b-c+d一样 (+-+)
//		中缀:a+b*(c-d)-e/f      
//		后缀:ab+cd*e/-f+  (左→右:中缀表达式)                             // 左→右,符号插在后面
//		前缀:+a-*b-cd/ef (右→左:中缀表达式 ,前缀表达式,也是右→左,运算顺序一致)  // 右→左,符号插在前面
//后缀表达式: a+b ---> ab+  运算符号插在后面。ab+c-d+ 从左往右(+-+)顺序计算--->运算顺序跟a+b-c+d一样 (+-+)

// 从“右”往“左”扫描   +						                  从“左”往“右”扫描	 +										
// 前缀表达式: +ab   ->  a  -> a+b (栈顶元素在:左边)           后缀表达式: ab+   ->  b  -> a+b (栈顶元素在:右边)  
//                        b		a在左边		             								 a     b在右边
//扫描顺序:先数字,再符号  就记住 a+b 这个例子就行,推一下就知道栈顶元素在哪个位置。


//*****************************************************************************************************************************************//
//相对名次 (第一题)
//输入:score = [5, 4, 3, 2, 1]
//输出:["Gold Medal", "Silver Medal", "Bronze Medal", "4", "5"]
//解释:名次为[1st, 2nd, 3rd, 4th, 5th]
class Solution {
	String[] ss = new String[]{ "Gold Medal", "Silver Medal", "Bronze Medal" };  //ss存储 1-2-3别名
	public String[] findRelativeRanks(int[] score) {                             //String[] 返回
		int n = score.length;                                                    //n 就是长度
		String[] ans = new String[n];
		int[] clone = score.clone();                //复制一份给clone   5-4-7-2-1
		Arrays.sort(clone);                         //Arrays.sort( )升序 (对数据进行改动,所以要克隆)    1-2-4-5-7
													//https://blog.csdn.net/Cherry_King/article/details/122783826
		Map<Integer, Integer> map = new HashMap<>();       //定义了一个 <int,int>类型 的哈希表
		//这个哈希表,花了我一个多小时,看半天,终于懂了    Map<Integer1, Integer2>   Integer1:值   Integer2:位置
																//当你 map.get(x) ,这里的x 就是Integer1,也就是  Integer2=map.get(Integer1)
		for (int i = n - 1; i >= 0; i--)                   //降序
			  map.put(clone[i], n - 1 - i);                // (7,0) (5,1) (4,2) (2,3) (1,4)
		for (int i = 0; i < n; i++) {
			int rank = map.get(score[i]);                  // rank=map.get(score[0])-->1  score里面的5在75421中排第二(0-1)
			ans[i] = rank < 3 ? ss[rank] : String.valueOf(rank + 1);   //位置 < 3 :0-1-2--->转化成Gold Siliver Bronze 不然的话,+1--->转化成字符串类型
		}															   //String.valueOf(rank + 1)  把rank+1 转化成 string                  
		return ans;
	}
}
//链接:https ://leetcode.cn/problems/relative-ranks/

//**************
class Solution {
	public String[] findRelativeRanks(int[] score) {      // 5-4-7-2-1
		int n = score.length;
		String[] desc = { "Gold Medal", "Silver Medal", "Bronze Medal" };
		int[][] arr = new int[n][2];

		for (int i = 0; i < n; ++i) {
			arr[i][0] = score[i];            
			arr[i][1] = i;
		}
		// 5,0	  7,2  第二个位置-->第一名   位置就很重要了   第一次接触,脑子真的太笨了,这玩意儿我都想了40多分钟
		// 4,1    5,0  第0个位置-->第二名
		// 7,2--->4,1  第一个位置-->第三名
		// 2,3    2,3  第3个位置-->第四名
		// 1,4    1,4  第4个位置-->第五名
		Arrays.sort(arr, (a, b)->b[0] - a[0]);    //第一个元素开始“降序”
		String[] ans = new String[n];
		for (int i = 0; i < n; ++i) {
			if (i >= 3) {
				ans[arr[i][1]] = Integer.toString(i + 1);
			}     
			else {
				ans[arr[i][1]] = desc[i];
			}
		}
		return ans;
	}

//链接:https ://leetcode.cn/problems/relative-ranks/

//Arrays.sort(boxTypes, (a, b)->b[0] - a[0]);//对二维数组进行排序
//
//首先复习下二维数组。其实二位数组就是一维数组,只是这个一位数组中的元素不是Int,String等基本类型而是Int[]。String[]数组类型。
//
//例子:int[][] arr = { {1,2,3,4,5},
//		{6,7,8,9,10},
//		{11,12,13,14,15},
//		{16,17,18,19,20}
//}
//
//这就是一个二位数组(本质上是一维,一共有4个元素。元素1: {1,2,3,4,5}, 元素2:{ 6,7,8,9,10),元素3:{11,12,13,14,15},元素4:{16,17,18,19,20})
//
// Arrays.sort(boxTypes, (a, b)->b[0] - a[0]),这句话是说我现在定了你的排序方法了,是按每一数组中的第一个数从大到小排序。按上面的例子来说就是
//
//排完序后:
//
//arr = {
//  {“16”,17,18,19,20},
//  {“11”,12,13,14,15},
//  {“6”,7,8,9,10},
//  {“1”,2,3,4,5}
//  }
//
//同理可得:Arrays.sort(boxTypes, (a, b)->b[3] - a[3]) 就是把每个数组中的第三个数组按从大到小的顺序进行比较。
//       (如果是Arrays.sort(boxTypes, (a, b)->a[3] - b[3]) 那就是)按从小到大的顺序进行比较)
//
//arr = {
//  {16,17,“18”,19,20},
//  {11,12,“13”,14,15},
//  {6,  7,“8”,9,10},
//  {1,  2,“3”,4,5}
//  }
// 
//*****************************************************************************************************************************************//
//设计一个找到数据流中第 k 大元素的类
//题目第k大的元素含义是“将数字从左到右降序排列后,从左边开始数的第k个数”。
//小根堆:门槛元素就是最小的,只有大于这个门槛元素的才能进入到堆里面
//因此,我们维护一个k长度的小根堆(相当于降序排序,最大的那个元素(第0大)在堆里面),那么堆顶元素就是第k大的元素

class KthLargest {
public:
	priority_queue<int, vector<int>, greater<int>> q;    //q 的小根堆   (头)1-2-3-5-7 
	int k;
	KthLargest(int k, vector<int>& nums) {
		this->k = k;
		for (auto& x : nums) {          //auto自动转换为 i 的数据类型 int  写 int x 都行········为啥 & ?
			add(x);      // x 就是nums的遍历
		}
	}
	int add(int val) {            //(头)1-2-3-5-7
		q.push(val);         //先按照小根堆放进q里面
		if (q.size() > k) {    //如果堆里面的元素超过k
			q.pop();           //那就继续删除顶部元素。直到3>3退出 (只留三个元素)
		}
		return q.top();      //刚开始1-2 3 5 7  
	}
};
//链接:https ://leetcode.cn/problems/kth-largest-element-in-a-stream/·······看不懂    简单题都做完了,突然懂了!哈哈哈

https://leetcode.cn/problems/kth-largest-element-in-a-stream/solutions/600652/python-dong-hua-shou-xie-shi-xian-dui-by-ypz2/
//跳过此题,此题用“小根堆”
//回过头来再看这题吧
//*****************************************************************************************************************************************//
 //最后一块石头的重量
//每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
//如果 x == y,那么两块石头都会被完全粉碎;
//如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y - x。
//最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。

//输入:[2, 7, 4, 1, 8, 1]
//输出:1
//解释:
//	先选出 7 和 8,得到 1,所以数组转换为[2, 4, 1, 1, 1],
//	再选出 2 和 4,得到 2,所以数组转换为[2, 1, 1, 1],
//	接着是 2 和 1,得到 1,所以数组转换为[1, 1, 1],
//	最后选出 1 和 1,得到 0,最终数组转换为[1],这就是最后剩下那块石头的重量。

class Solution {
	public int lastStoneWeight(int[] stones) {
		int index = stones.length - 1;
		for (int i = 0; i < stones.length - 1; i++) {     //最多比较length-1次
			Arrays.sort(stones);
			if (stones[index - 1] == 0) break;           //说明最多只剩一块石头
			stones[index] -= stones[index - 1];          //两种不同情况使用同一表达式处理
			stones[index - 1] = 0;                       //每次比较后肯定会有一块石头被destroyed
		}
		return stones[index];
	}
}
//*********************解释
class Solution {
	public int lastStoneWeight(int[] stones) {      // [1,2,1,4,7,8]
		int index = stones.length - 1;
//      index=4
		for (int i = 0; i < stones.length - 1; i++) {     //最多比较length-1次
			Arrays.sort(stones);																
			      //1,1,2,4,7,8   //0,1,1,1,2,4    //0,0,1,1,1,2   //0,0,0,1,1,1  //0,0,0,0,0,1
			if (stones[3] == 0) break;           //说明最多只剩一块石头							 //第三个是“0”,所以返回1
			stones[4] =stones[4] - stones[3];          //两种不同情况使用同一表达式处理       
			     //1,1,2,4, ,1    //0,1,1,1, ,2   //0,0,1,1, ,1   //0,0,0,1, ,0  
			stones[3] = 0;                       //每次比较后肯定会有一块石头被destroyed        
			    //1,1,2,4,0,1    //0,1,1,1,0,2   //0,0,1,1,0,1   //0,0,0,0,0,1
		}
		return stones[index];
	}
}
//···········好烦啊!又是通过小根堆做的,看不懂。回过头来,一定看看!     
// 我来啦!!第二天就懂了哈哈
方法一:最大堆
//找到最重的两个---->大根堆:头-次头        (头)8-7-6-5-1   
//头 - 次头=0:不用返回  >0:返回a-b
class Solution {
public:
	int lastStoneWeight(vector<int>& stones) {
		priority_queue<int> q;    //定义了q的大根堆
		for (int s : stones) {
			q.push(s);              //所有元素放进大根堆q里   
		}
		while (q.size() > 1) {     //只要多余一
			int a = q.top();       //a=top
			q.pop();               //别忘了删除
			int b = q.top();       //b=次top
			q.pop();
			if (a > b) {
				q.push(a - b);     //放进去,继续循环
			}
		}
		return q.empty() ? 0 : q.top();   //q.empty()--->  0  不是空的:q.top() 最后一个元素
	}
};
//链接:https ://leetcode.cn/problems/last-stone-weight/
//*****************************************************************************************************************************************//
//给你一个大小为 m* n 的矩阵 mat,矩阵由若干军人和平民组成,分别用 1 和 0 表示。
//请你返回矩阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。

class Solution {
	public int[] kWeakestRows(int[][] mat, int k) {
		int a = mat.length;
		int b = mat[1].length;
		int[][]aa = new int[a][2];
		int kk = 0;
		int sum = 0;
		for (int i = 0; i < mat.length; i++) {
			for (int j = 0; j < mat[i].length; j++) {
				sum += mat[i][j];
			}
			aa[kk][0] = sum;
			aa[kk][1] = kk;
			kk = kk + 1;
			sum = 0;
		}
		//Arrays.sort(aa);
		Arrays.sort(aa, (a, b)->b[0] - a[0]);
		int L[] = new int[k];
		for (int h = 0; h < k; h++) {
			L[h] = aa[h][1];
		}
		return L;
	}
}
//*****************************************************************************************************************************************//
//数组-1之后,两元素乘积最大
class Solution {
	public int maxProduct(int[] nums) {
		Arrays.sort(nums);                                   //升序                                   //遍历一次
		return (nums[nums.length - 1] - 1) * (nums[nums.length - 2] - 1);     //最后两个相乘          //遍历第二次
 	}
}
//链接:https ://leetcode.cn/problems/maximum-product-of-two-elements-in-an-array/

//只需要遍历一次,每次更新 最大,次大
int maxProduct(int* nums, int numsSize) {      //  大-小  A>大:A-大  A>小:大-A
	int a = nums[0], b = nums[1];            
	if (a < b) {
		int c = a;
		a = b;
		b = c;
	}
	for (int i = 2; i < numsSize; i++) {
		if (nums[i] > a) {
			b = a;
			a = nums[i];
		}
		else if (nums[i] > b) {
			b = nums[i];
		}
	}
	return (a - 1) * (b - 1);
}
//链接:https ://leetcode.cn/problems/maximum-product-of-two-elements-in-an-array/



//*****************************************************************************************************************************************//
//给你一个整数数组 nums 和一个整数 k 。你需要找到 nums 中长度为 k 的 子序列 ,且这个子序列的 和最大 。
class Solution {
	public int[] maxSubsequence(int[] nums, int k) {
		int n = nums.length;
		int[][] arr = new int[n][2];

		for (int i = 0; i < n; ++i) {                  //4,2,3,8-----> (4,0) (2.1) (3,2) (8,3)
			arr[i][0] = nums[i];
			arr[i][1] = i;
		}
		Arrays.sort(arr, (a, b)->b[0] - a[0]);        //降序   8-4-3-2
		int kk[][] = new int[k][2];
		for (int j = 0; j < k; j++) {                //只要前面k 个:8-4-3
			kk[j] = arr[j];                                      // (0-2-3)
		}
		Arrays.sort(kk, (a, b)->a[0] - b[0]);      //位序上升   //4-3-8    按照位序,才能保持原来位置输出。(如果两个数字相等,那就原位置输出)
		int ans[] = new int[k];
		for (int h = 0; h < k; h++) {
			ans[h] = kk[h][0];
		}
		return ans;
	}
}

//********************************************************************************************************************************************//
//给你一个正整数 num 。你可以交换 num 中 奇偶性 相同的任意两位数字(即,都是奇数或者偶数)。返回交换 任意 次之后 num 的 最大 可能值。
class Solution {
public:
	int largestInteger(int num) {
		string s = to_string(num);   // 转化为字符串
		int n = s.size();
		// 进行选择排序
		for (int i = 0; i < n - 1; ++i) {       //元素范围:0 -- n-1 (最后一个不用比较)    i<n 也行,不会错。
			for (int j = i + 1; j < n; ++j) {     //第i个和i后面(i+1)所有比较,后面的大,那就交换
				// 只有下标数值奇偶相同才进行判断
				if ((s[i] - s[j]) % 2 == 0 && s[i] < s[j]) {     //奇数-偶数=奇数 % 2!=0  所以通过这个就可以直接判断奇偶性是否相同
					swap(s[i], s[j]);
				}
			}
		}
		return stoi(s);   // 转化为最终的整数
	}
};
//链接:https ://leetcode.cn/problems/largest-number-after-digit-swaps-by-parity/
//********************************************************************************************************************************************//

class Solution {
public:
	int fillCups(vector<int>& amount) {
		int sec = 0;

		sort(amount.begin(), amount.end());
		while (amount[2] && amount[1]) {        //每次给需求最多的两杯倒水
			amount[2]--;
			amount[1]--;
			sec++;
			sort(amount.begin(), amount.end());
		}

		return sec + amount[2];
	}
};
//******************************
class Solution {
public:
	int fillCups(vector<int>& a) {
		return max({ a[0], a[1], a[2], (a[0] + a[1] + a[2] + 1) / 2 });
	}
};

链接:https ://leetcode.cn/problems/minimum-amount-of-time-to-fill-cups/
//**************************************************************************************************
// class Solution:
def fillCups(self, amount: List[int]) -> int :
	amount.sort()
	if amount[2] > amount[1] + amount[0]:   //反正就是最大值,直接:max({ a[0], a[1], a[2]})
return amount[2]
return (sum(amount) + 1) // 2        //整数除法,返回:整数 

链接:https ://leetcode.cn/problems/minimum-amount-of-time-to-fill-cups/

//***************************    accumulate(arr.begin(), arr.end(), 0, fun)
#include <iostream>
#include <numeric>
using namespace std;
int fun(int acc, int num) {
	return acc + num * 3;     // 计算数组中每个元素乘以3
}
int main() {
	vector<int> arr{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sum = accumulate(arr.begin(), arr.end(), 0, fun);            //accumulate(arr.begin(), arr.end(), 0, fun)
	cout << sum << endl;	// 输出 165
	return 0;
}
//************
int main() {
	vector<int> arr{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sum = accumulate(arr.begin(), arr.end(), 1, multiplies<int>()); // 初值1 * (1 * 2 * 3 * 4 *... * 10)   //multiplies<int>() 相乘
	cout << sum << endl;	// 输出3628800
	return 0;
}

//********************************************************************************************************************************************************//
//给你一个非负整数数组 nums 。在一步操作中,你必须:选出一个正整数 x ,x 需要小于或等于 nums 中 最小 的 非零 元素。
//nums 中的每个正整数都减去 x。返回使 nums 中所有元素都等于 0 需要的 最少 操作数。
//输入:nums = [1, 5, 0, 3, 5]
//输出:3            >0才判断:你画图,把数字变成高度。比如:1-2-3-4  那就-1-2-3-4 减四次(差不多)。但是,如果有相同的,那就砍一次就够了。
//解释:             
//	第一步操作:选出 x = 1 ,之后 nums = [0, 4, 0, 2, 4] 。            //核心: >0-----找不同
//	第二步操作:选出 x = 2 ,之后 nums = [0, 2, 0, 0, 2] 。
//	第三步操作:选出 x = 2 ,之后 nums = [0, 0, 0, 0, 0] 。
class Solution {
	public int minimumOperations(int[] nums) {
		Set<Integer> set = new HashSet<Integer>();
		for (int num : nums) {
			if (num > 0) {              //大于0开始判断
				set.add(num);           //set.add() 这时集合!!集合里面,不同元素才会加入
			}
		}
		return set.size();             //集合的长度就是不同元素的数量
	}
}
//链接:https ://leetcode.cn/problems/make-array-zero-by-subtracting-equal-amounts/

int array[10] = { 54, 23, 78, 9, 15, 18, 63, 33, 87, 66 };
for (int i = 0; i < 10; i++) {
	cout << array[i] << " ";	//这两句等价:遍历数组中所有元素的化简
	cout << a << " ";	        //输出:54 23 78 9 15 18 63 33 87 66
}
//******************************
class Solution {
public:
	int minimumOperations(vector<int>& nums) {
		sort(nums.begin(), nums.end());            //升序
		int res = 0, pre = 0;                //1 2 2 3 4 4 5 6
		for (auto i : nums) {                                       //升序的话,相同元素会集中在一起。可以通过 i==pre ,continue 跳过这个数字,继续循环
			if (i == pre) continue;        //刚开始第一个元素0的话,跳过  后来变成:pre=2 ,这时候如果是2,跳过,继续循环
			res++;               //记数不同元素数量
			pre = i;
		}
		return res;
	}
};

//****************************************************************************************************************************************//
给你一个 m x n 大小的矩阵 grid ,由若干正整数组成。
执行下述操作,直到 grid 变为空矩阵:
从每一行删除值最大的元素。如果存在多个这样的值,删除其中任何一个。
//本质就是:先删除每一行的最大值,然后,在所有行的最大值里找出最大的进行保留。最后求和
// 我们可以这么做:先给每一行进行升序。然后找到每一列最大值,进行求和就行。
//我写的:
class Solution {
	public int deleteGreatestValue(int[][] grid) {
		int len = grid.length;
		for (int j = 0; j < len; j++) {
			Arrays.sort(grid[j]);
		}
		int sum = 0;
		int p[] = new int[len];
		int le = grid[0].length;
		int f[] = new int[le];
		for (int k = 0; k < le; k++) {
			for (int u = 0; u < len; u++) {
				p[u] = grid[u][k];
			}
			int t = 0;
			Arrays.sort(p);
			f[t] = p[0];       //把列进行排序,取第一个元素,就是最大值
			t++;               //其实,直接用mx = Math.max(mx, grid[u][k]) 代替就行。不用那么麻烦
		}
		int summ = 0;
		for (int i = 0; i < f.length; i++) {
			summ += f[i];
		}
		return summ;
	}
}
//官方答案
class Solution {
	public int deleteGreatestValue(int[][] grid) {
		int len = grid.length;
		for (int j = 0; j < len; j++) {
			Arrays.sort(grid[j]);
		}
		int sum = 0;
		int p[] = new int[len];
		int le = grid[0].length;
		int f[] = new int[le];
		int mx = 0;
		for (int k = 0; k < le; k++) {
			for (int u = 0; u < len; u++) {
				mx = Math.max(mx, grid[u][k]);
			}
			int t = 0;
			f[t] = mx;
			t++;
		}
		int summ = 0;
		for (int i = 0; i < f.length; i++) {
			summ += f[i];
		}
		return summ;
	}
}

//*****************************************************************************************************************************************//
q.size();//返回q里元素个数
q.empty();//返回q是否为空,空则返回1,否则返回0
q.push(k);//在q的末尾插入k
q.pop();//删掉q的第一个元素
q.top();//返回q的第一个元素

priority_queue <int, vector<int>, greater<int> > pri_que;       //升序队列  小顶堆 great 小到大        (头) 1-2-“3”-4-5   加入的删掉
priority_queue <int, vector<int>, less<int> > pri_que;         //降序队列  大顶堆 less  大到小 默认    (头) 7-6-5-3-1
priority_queue<int> pq1; // 默认是最大堆...两种声明方式

//*****************************************************************************************************************************************//
给你一个整数数组 gifts ,表示各堆礼物的数量。每一秒,你需要执行以下操作:选择礼物数量最多的那一堆。
如果不止一堆都符合礼物数量最多,从中选择任一堆即可。
选中的那一堆留下平方根数量的礼物(向下取整),取走其他的礼物。
返回在 k 秒后剩下的礼物数量。
class Solution {
public:
	long long pickGifts(vector<int>& gifts, int k) {        
		priority_queue<int> q(gifts.begin(), gifts.end());    // 把q弄成大顶堆!!自动    //大根堆
		while (k--) {
			int x = q.top();    //返回头结点(最大的)
			q.pop();            //删除  (返回完,就立刻删除)
			q.push(int(sqrt(x)));    //插入 sqrt(x) 不一定插入最后。插入完,立刻插进该有的位置
		}
		long long res = 0;
		while (q.size()) {   //数量减少       堆得求和:拿出来,加上去,删除结点,一直重复。直到都删完了
			res += q.top();   //弹出头结点
			q.pop();      //删除
		}
		return res;
	}
};

class KthLargest {
public:
	priority_queue<int, vector<int>, greater<int>> q;    //q 的小根堆   (头)1-2-“3”-5-7-9-10 新来的,删头部。
	int k;
	KthLargest(int k, vector<int>& nums) {
		this->k = k;
		for (auto& x : nums) {          //auto自动转换为 i 的数据类型 int  写 int x 都行········为啥 & ?
			add(x);      // x 就是nums的遍历
		}
	}
	int add(int val) {            //(头)1-2-3-5-7
		q.push(val);         //先按照小根堆放进q里面
		if (q.size() > k) {    //如果堆里面的元素超过k
			q.pop();           //那就继续删除顶部元素。直到3>3退出 (只留三个元素)
		}
		return q.top();      //刚开始1-2 3 5 7  
	}
};
//链接:https ://leetcode.cn/problems/take-gifts-from-the-richest-pile/
//********************************************************************************************************************************************************//
//升级水桶:选择任意一个水桶,使其容量增加为 bucket[i] + 1
//蓄水:将全部水桶接满水,倒入各自对应的水缸
class Solution {
	public int storeWater(int[] bucket, int[] vat) {
		int len = bucket.length;
		int h = 0;
		int arr[][] = new int[len][2];
		for (int j = 0; j < len; j++) {
			if (bucket[j] == 0) {
				h = 2;
				bucket[j] = bucket[j] + 1;
				for (int i = 0; i < len; i++) {
					if (vat[i] == 0) {
						arr[i][0] = 0;
						continue;
					}
					int mx = 0;
					mx = Math.max(mx, vat[i] / bucket[i]);
					return  mx + 1;
				}
			}
		}
		if (h == 0) {
			for (int i = 0; i < len; i++) {
				if (vat[i] == 0) {
					arr[i][0] = 0;
					continue;
				}                                           错!!!!!!!!!!!
				arr[i][0] = vat[i] / bucket[i];
				arr[i][1] = i;
			}
			Arrays.sort(arr, (a, b)->b[0] - a[0]);
			int k = arr[0][1];
			bucket[k] = bucket[k] + 1;
		}
		int mx = 0;
		for (int w = 0; w < len; w++) {
			mx = Math.max(mx, vat[w] / bucket[w]);
		}
		return  mx + 1;

	}
}

//********************************************************************************************************************************************************//
//仓库管理员以数组 stock 形式记录商品库存表,其中 stock[i] 表示对应商品库存余量。请返回库存余量最少的 cnt 个商品余量,返回 顺序不限。
class Solution {
	public int[] inventoryManagement(int[] stock, int cnt) {       //最简单做法。但是,这么做肯定不行啊
		int[] vec = new int[cnt];    
		Arrays.sort(stock);         //上升
		for (int i = 0; i < cnt; ++i) {
			vec[i] = stock[i];
		}
		return vec;
	}
}
//链接:https ://leetcode.cn/problems/zui-xiao-de-kge-shu-lcof/
//***************************
class Solution {
public:
	vector<int> inventoryManagement(vector<int>& stock, int cnt) {
		vector<int> vec(cnt, 0);          // vec[]=0,?,?,?,?,?   (总共cnt个)
		if (cnt == 0) { // 排除 0 的情况                                       //int vec[]=new int [cnt];  ??为啥不行?
			return vec;    //vec=[0]
		}
		priority_queue<int> Q;         //大根堆  (头)8-7-6-2-1
		for (int i = 0; i < cnt; ++i) {
			Q.push(stock[i]);             //把前cnt个插入到大根堆里
		}
		for (int i = cnt; i < (int)stock.size(); ++i) {   //把后面的进行判断
			if (Q.top() > stock[i]) {     //如果前面cnt里最大的,比后面的大         //结果:后面只有小的,才能进去
				Q.pop();               //删除头结点
				Q.push(stock[i]);      ///把后面的插进去
			}
		}                   //cnt个最小
		for (int i = 0; i < cnt; ++i) {
			vec[i] = Q.top();    //最大的放进vec[0]     //次大的放进vec[1]      总之:大--较小--小 顺序输出
			Q.pop();             //删除最大的
		}
		return vec;
	}
};
//链接:https ://leetcode.cn/problems/zui-xiao-de-kge-shu-lcof/

//1、vector a(5); //定义了5个整型元素的向量(<>中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的。
//2、vector a(5, 1); //定义了5个整型元素的向量,且给出每个元素的初值为1
//3、vector a(b); //用b向量来创建a向量,整体复制性赋值
//4、vector a(b.begin(), b.begin + 3); //定义了a值为b中第0个到第2个(共3个)元素

//*****************************************************************************************************************************************//
//给你一个整数 n ,请你找出并返回第 n 个 丑数 。丑数 就是质因子只包含 2、3 和 5 的正整数。
class Solution {
public:
	int nthUglyNumber(int n) {
		vector<int> factors = { 2, 3, 5 };
		unordered_set<int> seen;			//无序的数组,可以动态扩容,不能重复                 //https://zhuanlan.zhihu.com/p/621889638
		priority_queue<int, vector<int>, greater<int>> heap;   //小根堆heap 
		seen.insert(1);						 //1L 是将数据转化为Long 数据类型,样子长得奇怪   写成1也行
		heap.push(1);                     
		int ugly = 0;
		for (int i = 0; i < n; i++) {
			int curr = heap.top();          //刚开始,curr=1   //第二次开始,取头元素(最小的)
			heap.pop();              //取完之后,别忘了删除
			ugly = curr;             //头元素                     //一直反复在所有next里面取最小的
			for (int factor : factors) {
				int next = curr * factor;   //1*2 1*3 1*5
				if (!seen.count(next)) {   //!seen.count(next)  :next不在seen里面的话   
					seen.insert(next);     //seen 加入if (!seen.count(next)) 后,像是“哈希表”
					heap.push(next);
				}
			}
		}
		return ugly;
	}
};
链接:https ://leetcode.cn/problems/ugly-number-ii/description/
//这道题,有点意思
	   2  4   6   8  10  12  14  16  18  20
	   3  6   9  12  15  18  21  24  27  30  
 	   5 10  15  20  25  30  35  40  45  50
//cur: 1  2   3  4   5   6   7   8   9   10  这样行吗?不行!cur不能等于7。只能是2 3 5倍数
//     1  2   3  4   5   6 “8”“9”“10”   “8”因为,8前面的所有数字里最小的!cur只能是倍数里面最小的。可以用“小根堆”

//***********  丑数 “最优解” 本质解法
// class Solution {
public int nthUglyNumber(int n) {
		   // ans 用作存储已有丑数(从下标 1 开始存储,第一个丑数为 1)
		   int[] ans = new int[n + 1];
		   ans[1] = 1;
		   // i2、i3 和 i5 分别代表三个有序序列当前使用到哪一位「已有丑数」下标(起始都指向 1)
		   for (int i2 = 1, i3 = 1, i5 = 1, idx = 2; idx <= n; idx++) {
			   // 由 ans[iX] * X 可得当前有序序列指向哪一位
			   int a = ans[i2] * 2, b = ans[i3] * 3, c = ans[i5] * 5;
			   int min = Math.min(a, Math.min(b, c));     // 将三个有序序列中的最小一位存入「已有丑数」序列
			   // 由于可能不同有序序列之间产生相同丑数,因此只要一样的丑数就跳过(不能使用 else if )
			   if (min == a) i2++;
			   if (min == b) i3++;            //并将其下标后移!!!核心   如果有相同的,都后移
			   if (min == c) i5++;
			   ans[idx] = min;
		   }
		   return ans[n];
	   }                             //此算法,不可能出现相同元素情况!本质解法。画图,比划一下就知道啦
}
//*****************************************************************************************************************************************//
//给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
class Solution {
public:
	vector<int> topKFrequent(vector<int>& nums, int k) {
		//1.map记录元素出现的次数                                     nums=1,5,4,3,3
		unordered_map<int, int>map;//两个int分别是元素和出现的次数              map= 1,2,3,4,5,6,7,8,9  (元素)
		for (int c : nums) {                                       //                0,0,0,0,0,0,0,0,0  (次数)      
			map[c]++;                                            //   第一个+1  第五个+1  第四个+1  第三个+1
		}                                                        //    0,1,0,2,1,1
		//2.利用优先队列,将出现次数排序
		//自定义优先队列的比较方式,小顶堆
		struct myComparison {
			bool operator()(pair<int, int>& p1, pair<int, int>& p2) {   
				//在C++中,Pair是一种将两个值绑定在一起的数据结构,可以将他们作为一个单元来处理。
			    //Pair是std命名空间中的一个类,它有两个成员——first和second。
				return p1.second > p2.second;//小顶堆是大于号
			}
		};
		//创建优先队列
		priority_queue<pair<int, int>, vector<pair<int, int>>, myComparison> q;
		//遍历map中的元素
		//1.管他是啥,先入队列,队列会自己排序将他放在合适的位置
		//2.若队列元素个数超过k,则将栈顶元素出栈(栈顶元素一定是最小的那个)
		for (int a : map) {
			q.push(a);
			if (q.size() > k) {
				q.pop();       //把最小得踢出去
			}
		}    //最后剩下最大的k个
		//将结果导出
		vector<int>res;
		while (!q.empty()) {        //只要不是空的
			res.emplace_back(q.top().first);      //emplace_back():在容器尾部添加一个元素  刚开始,添加的是最小得元素
			q.pop();      //删除这个
		}
		return res;

	}
	   };
//*****************************************************************************************************************************************//
struct fruit
{
	string name;
	int price;
};
//大顶堆               重载”<”
	   struct fruit
	   {
		   string name;
		   int price;
		   friend bool operator < (fruit f1, fruit f2)
		   {
			   return f1.peice < f2.price;
		   }
	   };

//小顶堆
struct fruit
{
	string name;
	int price;
	friend bool operator < (fruit f1, fruit f2)
	{
		return f1.peice > f2.price;  //此处是>
	}
};

//大顶堆   仿函数
struct myComparison
{
	bool operator () (fruit f1, fruit f2)
	{
		return f1.price < f2.price;
	}
};

//此时优先队列的定义应该如下
priority_queue<fruit, vector<fruit>, myComparison> q;

//*****************************************************************************************************************************************//
//pair
//在C++中,Pair是一种将两个值绑定在一起的数据结构,可以将他们作为一个单元来处理。
//Pair是std命名空间中的一个类,它有两个成员——first和second。
priority_queue<pair<int, int> > a;
pair<int, int> b(1, 2);
pair<int, int> c(1, 3);
pair<int, int> d(2, 5);
a.push(d);
a.push(c);
a.push(b);
while (!a.empty())
{
	cout << a.top().first << ' ' << a.top().second << '\n';
	a.pop();
}
//输出结果为:
2 5
1 3
1 2
//*****************************************************************************************************************************************//
//给定两个以 非递减顺序排列 的整数数组 nums1 和 nums2, 以及一个整数 k 。定义一对值(u, v),其中第一个元素来自 nums1,第二个元素来自 nums2 。
//请找到和最小的 k 个数对(u1, v1), (u2, v2)  ...  (uk, vk) 。








JAVA PriorityQueue 默认:小根堆
public boolean add(E e); //在队尾插入元素,插入失败时抛出异常,并调整堆结构
public boolean offer(E e); //在队尾插入元素,插入失败时抛出false,并调整堆结构

public E remove(); //获取队头元素并删除,并返回,失败时前者抛出异常,再调整堆结构
public E poll(); //获取队头元素并删除,并返回,失败时前者抛出null,再调整堆结构

public E element(); //返回队头元素(不删除),失败时前者抛出异常
public E peek();//返回队头元素(不删除),失败时前者抛出null

public boolean isEmpty(); //判断队列是否为空
public int size(); //获取队列中元素个数
public void clear(); //清空队列
public boolean contains(Object o); //判断队列中是否包含指定元素(从队头到队尾遍历)
public Iterator<E> iterator(); //迭代器

//********************************************************************************************************************************************************************************************//
//给你一个按递增顺序排序的数组 arr 和一个整数 k 。数组 arr 由 1 和若干 素数  组成,
//        且其中所有整数互不相同。对于每对满足 0 <= i < j < arr.length 的 i 和 j ,可以得到分数 arr[i] / arr[j] 。
//那么第 k 个最小的分数是多少呢 ? 以长度为 2 的整数数组返回你的答案, 这里 answer[0] == arr[i] 且 answer[1] == arr[j] 。

class Solution {                                           //学会了自定义堆
	public int[] kthSmallestPrimeFraction(int[] arr, int k) {
		int n = arr.length;
		PriorityQueue<int[]> q = new PriorityQueue<>((a, b)->Double.compare(b[0] * 1.0 / b[1], a[0] * 1.0 / a[1]));  
		                                  //后面的权重大,大根堆   不是说两个两个,而是一种规则!!!!
		for (int i = 0; i < n; i++) {      //开头开始:总的循环次数
			for (int j = i + 1; j < n; j++) {      //第二个元素开始:
				double t = arr[i] * 1.0 / arr[j];                                                         
				               //    q.add ( arr[i]/arr[j] )           q.peek(){[0][1]}
				if (q.size() < k || q.peek()[0] * 1.0 / q.peek()[1] > t) {       
					 //如果q.size() < k,没有满,继续插入    //如果满了,那就看后面:q.peek()[0] * 1.0 / q.peek()[1] > t,说明t小,小的就进入,把大的踢出去
					if (q.size() == k) q.poll();        //满的话,把大的踢出去。没有满的,不用踢,直接放就行。
					q.add(new int[] {arr[i], arr[j]});             
					    //先创建一个new int[],然后把{arr[i], arr[j]}放进去。 放进去的时候,arr[i]/arr[j]的比值大小顺序,大的在前面,插进去。                   
				}
			}
		}                             
		return q.poll();        //小的放进去,把头结点大的踢出去。最后,头结点就是第k个最小的元素
	}
}
//链接:https ://leetcode.cn/problems/k-th-smallest-prime-fraction/solutions/1127751/gong-shui-san-xie-yi-ti-shuang-jie-you-x-8ymk/

//*****************************************************   太难了!!没搞懂
class Solution {
	boolean flag = true;
	public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {                                   //1  7  11
		int n = nums1.length, m = nums2.length;                                                                    //2  4  6
		if (n > m && !(flag = false)) return kSmallestPairs(nums2, nums1, k);             
		       //flag=false :n>m    nums1大的话,把nums2给nums1,交换位置。保证nums1最小
		List<List<Integer>> ans = new ArrayList<>(); 
		PriorityQueue<int[]> q = new PriorityQueue<>((a, b)->(nums1[a[0]] + nums2[a[1]]) - (nums1[b[0]] + nums2[b[1]]));       //小根堆
		for (int i = 0; i < Math.min(n, k); i++) q.add(new int[] {i, 0});   
		        //相当于:(nums1[i],nums2[0])放入最小堆中      这个操作完,nums1:(头)小-------大进行了排列
		                                  0  1  2  放入小根堆之后:   头:(0,0)  (1,0)  (2,0)  ·····
									      0		····························· 
		while (ans.size() < k && !q.isEmpty()) {          
			      //容量<k,而且q不空情况下    因为,这个组合最多右 m*n 个。每次删掉最小的。如果k特别大的话,那就只能输出最后一个。
			int[] poll = q.poll();   
			    //头元素给poll   (1,2)   a=0   b=0    // (7,2)  a=0   b=1    //(11,2)  a=0  b=2
			int a = poll[0], b = poll[1];     
			     //a是第一个头元素  b是第二个头元素XXXXX     头结点( poll[0] , poll[1] )  (0,0)    //核心:b刚开始0开始   XXX
			ans.add(new ArrayList<>() {																									 
				{																							//  xxxx      小的在前面
					add(flag ? nums1[a] : nums2[b]);     //n小:true -->先a,后b    先输出小的  小的在上面		xxxxxxxxx
					add(flag ? nums2[b] : nums1[a]);
				}
			});
			if (b + 1 < m) q.add(new int[] {a, b + 1});      //b+1<m:说明下面还有         头:(0,0)  (1,0)  (2,0) +(0,1)
		}
		return ans;
	}
}
//链接:https ://leetcode.cn/problems/find-k-pairs-with-smallest-sums/
//*****************************************************************************************************************************************//

class Solution {
	public int kthSmallest(int[][] matrix, int k) {
		int rows = matrix.length, columns = matrix[0].length;    //rows是高度  columns是宽度
		int[] sorted = new int[rows * columns];             //搞一个数组,用来存放矩阵数字
		int index = 0;
		for (int[] row : matrix) {    //row 数组是矩阵每一行
			for (int num : row) {
				sorted[index++] = num;  //从第0个位置开始,把matrix从存放在sorted数组里面
			}
		}
		Arrays.sort(sorted);  //矩阵弄成一维数组,升序
		return sorted[k - 1];     //返回第k-1个
	}
}
//链接:https ://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/
//********************************************************************************************************************************************//
//给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
//请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。





class Solution {
	boolean flag = true;
	public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
		int n = nums1.length, m = nums2.length;
		if (n > m && !(flag = false)) return kSmallestPairs(nums2, nums1, k);              //flag=false :n>m
		
		PriorityQueue<int[]> q =
	 
		while (ans.size() < k && !q.isEmpty()) {           //容量<k,而且q不空情况下
			int[] poll = q.poll();   //头元素给poll
			int a = poll[0], b = poll[1];     //a是第一个头元素  b是第二个头元素
			ans.add(new ArrayList<>() {
				{
					add(flag ? nums1[a] : nums2[b]);     //n小:true -->先a,后b
					add(flag ? nums2[b] : nums1[a]);
				}
			});
			if (b + 1 < m) q.add(new int[] {a, b + 1});
		}
		return ans;
	}
}

//********************************************************************************************************************************************************************************************//
给定一个字符串 s ,对其按照字符出现次数降序排序。
class Solution {
public:                                      //tree
	string frequencySort(string s) {
		unordered_map<char, int> mp;           //char 作为值  int 作为位置     mp:t   r   e
		int length = s.length();                                                  1   1   2
		for (char ch : s) {                                                           ·······················
			mp[ch]++;
		}
		vector<pair<char, int>> vec;            // vec:(t,1)   (r,1)   (e,2)
		for (auto& it : mp) {                  //( char it:mp )
			vec.emplace_back(it);
		}
		sort(vec.begin(), vec.end(), [](const pair<char, int>& a, const pair<char, int>& b) {
			return a.second > b.second;       //sort排序定义了一个排序规则:看第二个值:谁大,谁在前面
			});                                // vec:(e,2)   (t,1)   (r,1)   
		string ret;
		for (auto& [ch, num] : vec) {           //auto& [ch, num]-----> char ch,int num   太香了!!自动转换。
			for (int i = 0; i < num; i++) {      // i<m:通过这个,可以一直输出相同的元素  
				ret.push_back(ch);               // (e,2):0<2----e e  (t,1):0<1-----t
			}
		}
		return ret;
	}
};
//链接:https ://leetcode.cn/problems/sort-characters-by-frequency/
//********************************************************************************************************************************************************************************************//
class Solution {
public:
	string frequencySort(string s) {
		unordered_map<char, int> mp;      //char 作为值  int 作为位置
		int maxFreq = 0;                 //出现最高的频率
		int length = s.size();            //字符串长度
		for (auto& ch : s) {            // ( char ch:s )
			maxFreq = max(maxFreq, ++mp[ch]);    //先+1,然后把出现频率大的留下来    mp:t   r   e
		}																     //			1   1   2
		vector<string> buckets(maxFreq + 1);      //创建桶:1---maxFreq 也有出现频率为0的,所以+1
		for (auto& [ch, num] : mp) {			  //mp: t r e e				//vec:(t,1)   (r,1)   (e,2)
			buckets[num].push_back(ch);										//vec:(t,1)  
		}
		string ret;
		for (int i = maxFreq; i > 0; i--) {
			string& bucket = buckets[i];
			for (auto& ch : bucket) {
				for (int k = 0; k < i; k++) {
					ret.push_back(ch);
				}
			}
		}
		return ret;
	}
};
//链接:https ://leetcode.cn/problems/sort-characters-by-frequency/
//********************************************************************************************************************************************************************************************//
//********************************************************************************************************************************************************************************************//
//****************************************************************************************				想把java学一遍																************************//
//********************************************************************************************************************************************************************************************//
//********************************************************************************************************************************************************************************************//

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值