【C++】map、set、multimap、multiset的介绍和使用

我讨厌世俗,也耐得住孤独。

在这里插入图片描述

文章目录

  • 一、键值对
  • 二、树形结构的关联式容器
    • 1.set
      • 1.1 set的介绍
      • 1.2 set的使用
      • 1.3 multiset的使用
    • 2.map
      • 2.1 map的介绍
      • 2.2 map的使用
      • 2.3 multimap的使用
  • 三、两道OJ题
    • 1.前K个高频单词(less<T>小于号是小的在左面升序,greater<T>大于号是大的在左面降序)
    • 2.两个数组的交集(排序+去重,简单的比对算法)



一、键值对

1.
之前所学的vector,list,deque等容器都是序列式容器,因为他们的底层数据结构都是线性的,并且数据结构中存储的都是元素数据本身,也就是单一的变量。
而下面所学的set、map、multimap、multiset等容器都是关联式容器,他们内部存储的不再是单一的元素数据,存储的而是<key,value>的键值对,由于每个键值对之间都有关联,所以其结构天生就具有优势,在数据检索时效率要比序列式容器高的多。

2.
那什么是键值对呢?键值对实际也是一个类,类里面对key和value数据进行了封装,key表示关键码,value表示与之对应的值,下面是SGI对于pair键值对结构体的定义:

3.
struct pair{}有两个构造函数,一个是无参的利用T1和T2类型的默认构造函数初始化出来的键值对,一个是T1和T2作为参数的构造函数。
另外pair还重载了两个运算符,用于键值对的等于和小于比较,小于比较时,优先比较first,如果first恰好满足x<y,则返回true。如果first之间相等,则比较失败返回false。如果first是x>y,那就继续比较second。
为了方便构造键值对,pair又另写了成员函数make_pair(),这个函数其实也是调用了构造函数,但在构造键值对的时候,省下我们自己去传T1和T2的类型了就。

template <class T1, class T2>
struct pair {
  typedef T1 first_type;
  typedef T2 second_type;

  T1 first;
  T2 second;
  pair() : first(T1()), second(T2()) {}
  pair(const T1& a, const T2& b) : first(a), second(b) {}

template <class T1, class T2>
inline bool operator==(const pair<T1, T2>& x, const pair<T1, T2>& y) { 
  return x.first == y.first && x.second == y.second; 
}

template <class T1, class T2>
inline bool operator<(const pair<T1, T2>& x, const pair<T1, T2>& y) { 
  return x.first < y.first || (!(y.first < x.first) && x.second < y.second); 
}

template <class T1, class T2>
inline pair<T1, T2> make_pair(const T1& x, const T2& y) {
  return pair<T1, T2>(x, y);
}

二、树形结构的关联式容器

根据应用场景的不同,STL总共实现了两种不同结构的管理式容器,一种是树型结构,一种是哈希结构,树型结构的关联式容器主要分为map、set、multimap、multiset。
这四种容器的共同点是都是用平衡搜索树(红黑树)作为底层结构

1.set

1.1 set的介绍

1.
在set中,key和value是同时被标识的,所以key就是value,正由于key就是value,所以set容器中的元素不允许被修改,每个元素都被const修饰,只能增insert删erase查find。

2.
set在比较时默认使用缺省的仿函数less< T >,所以一旦比较成功时,较小元素就被插入到左边,较大元素就被插入到右边,那么在中序遍历时,结果自然就是升序结果。如果改为greater< T >,则逻辑就会反过来,中序遍历结果就是降序。

在这里插入图片描述
3.
set与map不同的是,map存放的是真正的键值对<key,value>,而set中只放value,但在底层实际存放的是<key,key>的键值对。

在这里插入图片描述
4.
set不允许元素被修改,因为这会破坏搜索树的结构。

5.
set中不允许元素有重复,所以set和二叉搜索树比较像,一旦元素重复再进行插入时,情况就较为复杂,需要用到树的旋转等知识,不过multiset可以支持插入的元素重复。
在使用set迭代器进行遍历时,set的迭代器走的是中序遍历的顺序,每一个迭代器都指向对应位置的键值对,当然set容器的元素我们也可以叫做键值对,只不过key和value相等罢了。

6.
由于set中不允许有元素重复,所以将一段数据插入到set时,set所展现的功能是排序+去重。

1.2 set的使用

1.
set的insert有三个重载形式,较为常用的就是直接插入一个值和利用其他容器的迭代器区间构建出set容器。

在这里插入图片描述

2.
erase用于删除set中的某个元素,如果删除成功,则返回1,否则返回0,size_type是unsigned int typedef出来的。

在这里插入图片描述

3.
find用于查找set中某个元素val,找到就返回键值对对应的迭代器,否则就返回end迭代器。
算法库中也有find,但哪个find的效率明显要低于set类的find,因为一个是类似于二分查找,一个是暴力通过迭代器进行查找,一个是logN,一个是N

在这里插入图片描述
在这里插入图片描述

void test_set1()
{
	set<int,greater<int>> s;
	s.insert(3);
	s.insert(1);
	s.insert(4);
	s.insert(7);
	s.insert(2);
	s.insert(1);

	//set底层是二叉搜索树,当插入相同的值时会返回false,所以set是排序+去重
	set<int,greater<int>>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	//auto pos = s.find(3);
	auto pos = find(s.begin(), s.end(), 3);//算法库的find其实就是利用迭代器进行查找,找不到就返回end()迭代器
	//上面这两行代码的查找结果相同,但34行的效率肯定更高一些,因为35行是暴力查找,34行借助搜索树的特性查找高度次
	//如果是平衡的搜索树,则效率是O(logN)。暴力查找的效率是O(N),即一个一个迭代器的遍历进行查找。
	if (pos != s.end())
	{
		s.erase(pos);
	}
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << s.erase(10) << endl;//返回0表示没有删除
	cout << s.erase(1) << endl;//返回1表示删除
	//上面代码等价于find+erase,删除元素也是要先找再删,找到就删,没找到就直接返回。
}

1.3 multiset的使用

1.
multiset与set的唯一区别就是允许元素重复,其余并没有什么区别,所以用multiset进行排序时,仅仅只能排序,没有去重的效果。
在set中count可能没有什么用,因为每个键值对都只能出现一次,不允许元素重复,但count在multiset中就有用了,可以统计某个key在set中共出现了几次。

在这里插入图片描述

#include <set>
void TestSet()
{
	int array[] = { 2, 1, 3, 9, 6, 0, 5, 8, 4, 7 };
	// 注意:multiset在底层实际存储的是<int, int>的键值对
 	multiset<int> s(array, array + sizeof(array)/sizeof(array[0]));
	for (auto& e : s)
		cout << e << " ";
	cout << endl;
	return 0;
}

2.
在set和multiset中都有lower_bound和upper_bound接口,bound是约束束缚的意思,可以用于set中某一上限和下限区间元素的删除,有一说一,这俩接口确实不常用。

在这里插入图片描述

2.map

2.1 map的介绍

1.
map存储的是key和value组成的键值对元素结构体,在比较时按照key来进行比较,下面源码我们可以看到key依旧是不允许被修改的,但其对应的value是可以被修改的。

在这里插入图片描述
2.
map中比较时比较的是key类型,但我们可以通过key找到value,这里多说一句,无论是map还是set,他们的迭代器走的都是中序的顺序。

在这里插入图片描述

2.2 map的使用

1.
map和set都有三个构造函数,其中无参构造函数最为常用,平常在使用map或set时,直接定义其对象即可,无须传参,大多数情况下都是这样。

在这里插入图片描述
在这里插入图片描述
2.
map和set在插入后都会返回一个键值对:
键值对的first是迭代器,其指向的是新插入键值对,若新插入键值对的key已经存在,则返回已经存在的key对应的键值对的迭代器,这是first的变化规则。
键值对的second是bool值,如果插入的key已经存在,则bool为false,否则bool为true。

在这里插入图片描述
3.
map的迭代器访问这里有讲究,由于其迭代器指向的是由key和value组成的键值对,那* it该获得哪个key和value的哪个值呢?set的迭代器指向的就只有key,所以* it直接返回key值即可。
对于map来说,*it拿到的是pair的对象,所以我们还需要再加一个.操作符才能访问pair对象里面的first和second值,但这样写起来有点麻烦,所以map的迭代器也重载了→操作符,→重载的函数会返回迭代器指向对象的地址,所以还应该再加个→访问first或second才对,但是编译器在这里做了优化,省略了一个箭头。(这部分其实在list迭代器那里就说过了,这里正好做一下复习)

4.
在map这里,如果我们用语法糖遍历map时,最好采用const引用,因为map中存的是键值对pair,不用引用就会发生赋值,会调用pair的赋值重载函数,代价比较大,为了提升效率建议采用const引用。(语法糖遍历拿到的值其实就是*it,在map这里就是pair对象,键值对)

int main()
{
	map<string, string> dict;
	dict.insert(pair<string, string>("苹果", "apple"));
	dict.insert(pair<string, string>("鸭梨", "pear"));
	dict.insert(pair<string, string>("西瓜", "watermelon"));
	dict.insert(make_pair("草莓", "strawberry"));//make_pair是一个函数模板,内部调用pair的构造函数,但隐式实例化可以减少代码
	dict["迭代器"] = "iterator";// 插入+修改

	dict["insert"];// key不在就是插入,value用string的默认构造
	dict.insert(pair<string, string>("鸭梨", "xxxx"));//这个插入不进去,搜索树的鸭梨已经存在了
	dict["insert"] = "插入";// insert已经存在,这里表示修改insert的value值
	cout << dict["insert"] << endl;//key已经存在,这里相当于查找,[]会返回关键码对应的value值,查找时必须确定key已经存在于map
	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		//如果结点定义成key和value两个变量,*it都不知道返回谁的值。所以返回pair对象,这样就可以访问两个值了
		//cout << (*it).first << ":" << (*it).second << endl;
		cout << it->first << ":" << it->second << endl;//底层是pair封装了value和key,并实现运算符重载

		it++;
	}


	for (const auto& kv : dict)//kv就相当于*it,取到的是map中存储的结构体对象pair
	//现在的kv已经不像以前一样,仅仅是个内置类型,而是一个结构体对象,结构体的对象进行赋值调用函数代价太大,所以我们用引用
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

5.
如果用map来统计水果出现的次数,我们采用的思路可以是,如果key不在,那就将键值对插入map,键值对的int初始值设置为1。如果key在,那就把key对应的value值+1,最后语法糖遍历一下map,就可以拿到中序遍历的结果,也就是统计出了水果出现的次数。

6.
另外还有一种非常骚的操作就是利用map的[ ]来统计次数,在前面了解了insert的返回值之后,再来理解map的[ ]调用成本就会低很多了,实际上[ ]带来的作用包括插入,查找,修改的功能,直接一个[ ]运算符重载包揽map的三个重要功能。

7.
拥有这么多功能其实还是因为调用了insert,insert在插入时的键值对的key由我们来传参,而value用其对应类型的匿名构造来代替,所以如果key不存在,那insert就表示插入,如果key已经存在,则[ ]既可以修改,又可以查找。

在这里插入图片描述
在这里插入图片描述

8.
所以用[ ]可以直接统计出次数,将对应的arr每个元素插入到map里面,如果key存在,则[ ]内部的insert会返回已经存在的key对应的迭代器,通过此迭代器可以拿到value的引用,又因为int类型匿名构造是0,则value初始化是0,++就是1,所以countMap.[e]++就可以直接统计出水果出现的次数。

int main()
{
	//定义一个map统计水果出现的次数
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
				"苹果", "香蕉", "苹果", "香蕉" ,"草莓","草莓", "香蕉", "西瓜", };
	map<string, int> countMap;
	//for (auto& e : arr)
	//{
	//	//map<string, int>::iterator it = countMap.find(e);
	//	auto it = countMap.find(e);
	//	if (it == countMap.end())
	//		countMap.insert(make_pair(e, 1));
	//	else
	//		it->second++;
	//}
	for (auto& e : arr)
	{
		countMap[e]++;
		//  (   *(   (this->insert(make_pair(k, mapped_type()))).first  )   ).second 

		//迭代器指向的是pair类实例化的对象,我们称这个对象为键值对
	}
	for (const auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}

	return 0;
}

9.
注意:在元素访问时,有一个与operator[]类似的操作at()(该函数不常用)函数,都是通过
key找到与key对应的value然后返回其引用,不同的是:当key不存在时,operator[]用默认
value与key构造键值对然后插入,返回该默认value,at()函数直接抛异常

2.3 multimap的使用

1.
multimap是没有[ ]的,因为multimap支持key值进行重复,那[ ]返回哪个key的引用呢?太乱了吧,所以multimap没有重载[ ]运算符。其余接口的使用和map一样,这里不作介绍。

三、两道OJ题

1.前K个高频单词(less小于号是小的在左面升序,greater大于号是大的在左面降序)

前K个高频单词

1.
我们可以用排序的思路来解决这道题,定义string和int的键值对,然后将所有单词存到map里面,这样map里面就有单词和单词出现的次数的键值对了,并且string还是按照字典顺序排好了。然后我们将键值对利用sort来进行排序,但由于map的迭代器是双向迭代器,而sort要求支持随机访问,因为他底层是快排,那就需要随机迭代器,所以我们将map中的键值对语法糖式的尾插到vector里面,vector的迭代器是随机迭代器,可以适用于快排。

2.
比较vector中的键值对时,快排是不稳定的,当两个单词的出现次数一样时,那在快排比较的时候是有可能打乱两个单词在vector里面出现的顺序的,所以我们可以采取stable_sort进行排序,代码里面写出了错误示范,其实问题不仅仅出现在sort上面,而是出现在pair的比较规则上面去了,所以要想解决问题,还是得从排序的比较规则上面入手,我们重写仿函数,自己定义比较的规则就好了,让这个比较规则契合题目逻辑。

快排的确是不稳定的,这确实没毛病。
在这里插入图片描述
在这里插入图片描述

3.
sort排序想要正确,他的仿函数逻辑要分两种情况,一种是只有左边键值对的次数大于右边时才可以交换,另一种是关键,因为快排不是不稳定么,那我们就调整逻辑让他稳定,当次数相等时,必须保证second的相对顺序不变,不能随意交换。那就增加条件为:左边的string小于右边的string才返回true。
(这个地方你可以这么理解,因为算法库中默认的less排升序,less里面是小于号,那就是小的在左面,greater排降序,greater里面是大于号,大的在左面,这样理解的话,当次数相同时我们想让字符串小的在左面,那就应该用小于号进行比较,所以仿函数里面second比较那里用小于号

4.
这里并没有改变sort的稳定性,只是调整了比较的逻辑,如果不控制first相等时的string顺序,那快排就会随意打乱次数相等的单词,但这并不是我们想看到的,所以我们现在强行控制逻辑,不让快排打乱单词的顺序,必须按照字典顺序保证string小的单词在左面

class Solution {
public:
    struct compare
    {
        bool operator()(const pair<int, string>& left, const pair<int, string>& right)
        {
            return left.first > right.first || (left.first==right.first && left.second < right.second);//second用小于号比较
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        vector<string> ret;
        map<string, int> mp;
        for(const auto& str : words)
        {
            mp[str]++;
        }
        vector<pair<int, string>> v;//用vector来排序,map是双向迭代器,不支持随机访问
        for(const auto& kv : mp)
        {
            v.push_back(make_pair(kv.second, kv.first));
        }
        //第一个是错误写法示例,greater排降序,但pair默认的比较规则不符合题目要求
        stable_sort(v.begin(), v.end(), greater<pair<int ,string>>);
        sort(v.begin(), v.end(), compare());

        for(int i=0; i<k; i++)
        {
            ret.push_back(v[i].second);
        }
        return ret;

    }
};

5.
下面采用稳定排序的方式进行排序,稳定排序不用考虑first相等时单词有可能被打乱顺序的情况,因为稳定排序不会打乱相等值的相对顺序。

6.
所以仿函数逻辑就是,只有左边的键值对的first大于右边的first(vector中键值对的first是单词出现次数)时,我们才会返回true,进行交换,其他相等或小于的情况都不允许交换,这样就可以保证大的在左面,就能完成降序的工作了。

在这里插入图片描述

class Solution {
public:
    struct compare
    {
        bool operator()(pair<int, string> left, pair<int, string> right)
        {
            return left.first > right.first;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        vector<string> ret;
        map<string, int> mp;
        for(const auto& str : words)
        {
            mp[str]++;
        }
        vector<pair<int, string>> v;//用vector来排序,map是双向迭代器,不支持随机访问
        for(const auto& kv : mp)
        {
            v.push_back(make_pair(kv.second, kv.first));
        }
        stable_sort(v.begin(), v.end(), compare());

        for(int i=0; i<k; i++)
        {
            ret.push_back(v[i].second);
        }
        return ret;

    }
};

2.两个数组的交集(排序+去重,简单的比对算法)

两个数组的交集

1.
这道题目就比较简单了,我们可以利用set先进行排序+去重,然后比较两个set里面的值,如果两个值相等时,说明这个值是两个数组的交集,两个迭代器同时往后走,去后面继续比较,如果不相等,那就让较小元素对应的迭代器往后++,因为在小元素的后面才会有可能和另一个set当前的值相等。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> ret;
        set<int> s1(nums1.begin(), nums1.end());
        set<int> s2(nums2.begin(), nums2.end());
        auto it1 = s1.begin();
        auto it2 = s2.begin();
        while(it1 != s1.end() && it2 != s2.end())
        {
            if(*it1 < *it2)
            {
                it1++;
            }
            else if(*it1 > *it2)
            {
                it2++;
            }
            else
            {
                ret.push_back(*it1);
                it1++;
                it2++;
            }
        }
        return ret;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/3264.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何将字符串反转?

参考答案 使用 StringBuilder 或 StringBuffer 的 reverse 方法&#xff0c;本质都调用了它们的父类 AbstractStringBuilder 的 reverse 方法实现。&#xff08;JDK1.8&#xff09;不考虑字符串中的字符是否是 Unicode 编码&#xff0c;自己实现。递归1. public AbstractStrin…

优秀程序员的5个特征,你在第几层?

每个人程序员都对未来的职业发展有着憧憬和规划&#xff0c;要做架构师、要做技术总监、要做CTO。但现实总是复杂的&#xff0c;日复一日的工作与生活总能让人一次又一次地陷入迷茫。大部分原因就是对职业发展轨迹和自我能力提升的一般规律缺乏认识&#xff0c;做事找不到方向或…

WebSocket 测试工具

一、WebSocket 简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直…

MySQL数据库管理系统安装部署——Linux

MySQL数据库管理系统安装部署——Linux 简介 MySQL数据库管理系统&#xff08;后续简称MySQL)&#xff0c;是一款知名的数据库系统&#xff0c;其特点是:轻量、简单、功能丰富。MySQL数据库可谓是软件行业的明星产品&#xff0c;无论是后端开发、大数据、AI、运维、测试等各类…

linux入门---操作体统的概念

什么是操作系统 操作系统是一个对软硬件资源进行管理的软件。计算机由一堆硬件组成&#xff0c;这些硬件遵循着冯诺依曼体系结构 在这个硬件的基础上还有一个软件叫做操作系统 操作系统的任务是对硬件进行管理&#xff0c;既然是管理的话操作系统得访问到底层的硬件&#xf…

【贪心算法】一文让你学会“贪心”(贪心算法详解及经典案例)

文章目录前言如何理解“贪心算法”&#xff1f;贪心算法实战分析1.分糖果2.钱币找零3.区间覆盖内容小结最后说一句&#x1f431;‍&#x1f409;作者简介&#xff1a;大家好&#xff0c;我是黑洞晓威&#xff0c;一名大二学生&#xff0c;希望和大家一起进步。 &#x1f47f;本…

Spring Boot 各层作用与联系

目录 1 Entity 层 2 DAO 层 3 Service 层 4 Controller 层 Spring Boot 各层之间的联系&#xff1a; controller 层-----> service 层(接口->接口实现类) -----> dao 层的.mapper 文件 -----> 和 mapper 层里的.xml 文件对应 1 Entity 层 实体层&#xff0c;…

Java笔记_6(面向对象)

Java笔记_6一、面向对象1.1、设计对象并使用1.2、封装1.3、就近原则和this关键字1.4、构造方法1.5、标准的JavaBean类1.6、对象内存图1.7、基本数据类型和引用数据类型1.8、this的内存原理1.9、成员和局部二、面向对象&#xff08;综合练习&#xff09;2.1、文字版格斗游戏2.2、…

正式环境关闭swagger

直接上步骤&#xff0c;如图&#xff1a;1&#xff0c;启动判断写在相应的环境配置文件中&#xff0c;根据条件判断是否启动 swagger &#xff1a;添加配置项&#xff1a;swagger.is.enable配置文件中添加&#xff1a;#是否激活 swagger true or falseswagger.is.enabletrue2&a…

【Linux】-初识Linux

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【Linux】 分享&#xff1a;逆着光行走&#xff0c;任风吹雨打。 ——《起风了》 主要内容&#xff1a;Linux的一些最基本指令&#xff0c;Linux的小程序&#xff0c;Linux关于连…

从暴力递归到动态规划(2)小乖,你也在为转移方程而烦恼吗?

前引&#xff1a;继上篇我们讲到暴力递归的过程&#xff0c;这一篇blog我们将继续对从暴力递归到动态规划的实现过程&#xff0c;与上篇类似&#xff0c;我们依然采用题目的方式对其转化过程进行论述。上篇博客&#xff1a;https://blog.csdn.net/m0_65431718/article/details/…

看完这篇 教你玩转渗透测试靶机vulnhub——My File Server: 1

Vulnhub靶机My File Server: 1渗透测试详解Vulnhub靶机介绍&#xff1a;Vulnhub靶机下载&#xff1a;Vulnhub靶机安装&#xff1a;Vulnhub靶机漏洞详解&#xff1a;①&#xff1a;信息收集&#xff1a;②&#xff1a;FTP匿名登入&#xff1a;③&#xff1a;SMB共享服务&#xf…

【微信小程序】-- 使用 Git 管理项目(五十)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

【Docker】Compose容器编排LNMP上云

文章目录什么是Docker-Compose下载安装官网官网下载安装卸载Compose核心概念一文件两要素三个步骤Compose常用命令DjangoMysqlRedisNginx部署部署架构构建django容器 - - - dockerfile编写构建Nginx容器docker-compose 编排容器Django项目配置custom_webmysql容器redis容器Djan…

一文看懂数据仓库

数据仓库数据仓库的概念数据仓库的主要特征数据仓库的分层数据仓库的分层介绍原始数据层&#xff1a;ODS&#xff08;Operational Data Store&#xff09;数据仓库层&#xff1a;DW&#xff08;Data Warehouse&#xff09;数据明细层&#xff1a;DWD&#xff08;Data Warehouse…

邪恶的想法冒出,立马启动python实现美女通通下

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 完整源码、python资料: 点击此处跳转文末名片获取 当我在首页刷到这些的时候~ 我的心里逐渐浮现一个邪念&#xff1a;我把这些小姐姐全都采集&#xff0c;可以嘛&#xff1f; 答案当然是可以的~毕竟就我这技术&#xff0c…

【Java|golang】45. 跳跃游戏 II

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最…

不会写SQL?ChatGPT 来帮你

想必当前最火的软件就是ChaGPT了&#xff0c;它是一款基于人工智能技术的大型语言模型,在数据库方面&#xff0c;ChaGPT可以被用来进行自然语言处理&#xff0c;实现自然语言查询和分析数据库。通过将ChaGPT与数据库集成&#xff0c;可以使得数据库更加智能化&#xff0c;提高数…

【2023】Kubernetes-网络原理

目录kubernetes网络模型kubernetes网络实现容器到容器之间通信Pod之间的通信Pod到Service之间的通信集群内部与外部组件之间的通信开源容器网络方案FlannelCalicokubernetes网络模型 Kubernetes网络模型设计的一个基础原则是&#xff1a;每个Pod都拥有一个独立的IP地址&#x…

【Android -- 软技能】《软技能:代码之外的生存指南》之好书推荐(一)

前言 这是一本由美国的一个软件开发人员写的&#xff0c;但书中除了有 Java 、C# 几个单词外&#xff0c;没有一行代码。 因为这本书讲的是代码之外的东西。 文章目录结构&#xff1a; 1. 职业 从业心态&#xff1a;说白了就是要有责任心&#xff0c;把每份工作要当成是自…
最新文章