//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学一遍 ************************//
//********************************************************************************************************************************************************************************************//
//********************************************************************************************************************************************************************************************//
堆,队列,递归(笔记+刷题)
于 2023-11-28 19:10:44 首次发布