数组:
//在连续空间存储相同类型的元素。
1、定义数组:int arr1[5] = {1 , 2, 4 ,5}; int a[100] = {0};
2、数组的大小: n = sizeof a/sizeof(int)
1、最大连续的1的个数
//输入:[1,1,0,1,1,1] 输出:3
class Solution {
public:
int findMaxConsecutiveOnes(vector<int>& nums) {
int count =0;
int maxcount = 0;
for(int i = 0 ;i < nums.size();i++) {
if(nums[i] == 1) {
count++;
}
else {
maxcount = max(maxcount,count);
count = 0;
}
}
maxcount = max(maxcount,count); //最大连续的1的个数可能出现在最后
return maxcount;
}
};
2、移动零
//输入: [0,1,0,3,12] 输出: [1,3,12,0,0]
//第一种直接覆盖
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int n = nums.size();
int index = 0;
for(int i=0;i < n;i++) {
if(nums[i] != 0) {
nums[index++] = nums[i];
}
}
while(index < n) {
nums[index++] =0;
}
}
};
3、移除元素
//移除一个数组中所有等于val的元素,并返回数组新的长度
//输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2]
//思想和上一个一样,主要就是可以看成2个数组,一个指向一个,然后寻找符合的元素按照index顺序排好,其余元素添0.
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int index = 0;
for(int i = 0 ; i < n; i++) {
if(nums[i] != val) {
nums[index++] =nums[i];
}
}
return index;
}
};
链表:
1、创建链表 2、添加元素 3、访问元素
4、查找元素 5、删除元素 6、链表长度
//链表定义
ListNode* head = new ListNode(5);
//ListNode* head = new ListNode();
//head->val = 5; 数值为5 的节点
//用来定义单链表结构
struct node
{
int data; //数据域
node* next; //指针域
};
class list
{
node* head;
public:
list()
{
head = new node;//创建堆区 指针head指向node堆区的首地址,然后让其指向空
head->next = NULL; //NUll为一个空地址
}
};
1、删除链表元素
//输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* };
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
//删除头节点
while (head !=NULL && head->val == val) {
ListNode * tmp = head;
head = head->next;
delete tmp;
}
//删除非头结点
ListNode *p = head;
while(p != NULL && p->next != NULL ) {
if(p->next->val == val) {
ListNode *tmp= p->next;
p->next = p->next->next;
delete tmp;
}
else {
p =p->next;
}
}
return head;
}
};
2、反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* temp; // 保存cur的下一个节点
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur->next = pre; // 翻转操作
// 更新pre 和 cur指针
pre = cur;
cur = temp;
}
return pre;
}
};
3、判断链表是否有环
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,说明有环
if (slow == fast) return true;
}
return false;
}
};
//slow指针走过的节点数为: x + y, fast指针走过的节点数:x + y + n (y + z)
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};
4、链表倒数第k个元素
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyNode = new ListNode(0, head);
ListNode* slow = dummyNode;
ListNode* fast = dummyNode;
//令slow和fast距离相差n
while (n--) {
fast = fast->next;
}
//令fast最终停留在尾结点,因为slow和fast相差n,则slow位置为尾结点的前n个位置,即slow为整个链表倒数第n+1个结点,也就是第n个结点的前驱结点
while (fast->next) {
fast = fast->next;
slow = slow->next;
}
//令倒数第n个结点的前驱结点指向其下一结点的next
slow->next = slow->next->next;
return dummyNode->next;
}
};
队列:
//先进先出 相当于一个管道 一端进一端出
queue容器 相当于队列,先进先出
q.push() //队尾进入数据 q.back() //返回最后一个元素
q.pop() //队头出数据 q.front() //返回第一个元素
//单端队列 一个口只能进,一个口可以出
//插入 只能插到最后 删除只能删除头
//创建队列 添加元素 获取元素 删除元素 判断队列是否为空 队列长度 遍历队列(边遍历边删除)
1、最近的请求次数
//["RecentCounter", "ping", "ping", "ping", "ping"][[], [1], [100], [3001], [3002]]
//输出:[null, 1, 2, 3, 3]
class RecentCounter {
public:
RecentCounter() {}
//使用队列,一直检查队列头部和插入时间是否大于3000,大于就弹出
int ping(int t) {
q.push(t);
while( t - q.front() > 3000) {
q.pop();
}
return q.size();
}
private:
queue<int> q;
};
2、滑动窗口最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> q;
//在队列后面添加数据,把前面数据小的全部删除。
vector<int> ans;
for(int i = 0 ;i < nums.size(); i++) {
//当前遍历的元素的值比队尾大,让队尾元素出去
while(! q.empty() && q.back() < nums[i] ) {
q.pop_back();
}
//当遍历的元素入栈,那么队列的元素头部最大
q.push_back(nums[i]);
//如果窗口满状态,就可以得到窗口最大值啦
if(i >= k - 1) {
ans.push_back(q.front());
if(nums[i - k + 1] == q.front()) {
q.pop_front();
}
}
}
return ans;
}
};
栈(stack):
先进后出 : A B C -> C B A
1、怎么创建栈
1、有效括号
class Solution {
public:
bool isValid(string s) {
int n = s.size();
if(n % 2 == 1) return false;
unordered_map<char, char> pair = { {')', '('},{']', '['},{'}', '{'}};
stack<char> stk;
for(char ch : s) { //在s中遍历 字符串s中全部字符的存在
//左括号压进栈,后面进入的先匹配
if(pair.count(ch)) { //字符ch对应键值个数的多少
if(stk.empty() || stk.top() != pair[ch]) return false;
stk.pop();
}
else stk.push(ch);
}
return stk.empty();
}
};
class Solution {
public:
bool isValid(string s) {
stack<char> st;
for(int i = 0; i < s.size(); i++) { // if else 互斥 只能执行一个
if (s[i] == '(') st.push(')'); //先进匹配,如果 有左括号,就压进去右括号,
else if (s[i] == '{') st.push('}');
else if (s[i] == '[') st.push(']');
else if (st.empty() || st.top() != s[i]) return false;
else st.pop(); // st.top() 与 s[i]相等,栈弹出元素
}
return st.empty();
}
};
2、下一个更大元素
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> s; //记录数组的值
//主要就先求出,主数组的下一个更大元素,然后直接匹配
//转换成查找后面元素是否大的问题
unordered_map <int,int> map; //存放下一个最大值
for(int i = nums2.size() - 1 ;i >=0; i--) {
while(! s.empty() && s.top() <= nums2[i]) {
s.pop();
}
map[nums2[i]] = s.empty() ? -1: s.top();
s.push(nums2[i]);
}
for(int i = 0; i < nums1.size();i++) {
nums1[i] = map[nums1[i]];
}
return nums1;
}
};
哈希表:
哈希表:key : value 可以通过key得到value
通过key值 哈希函数对应,找到内存地址
1、哈希碰撞:两个不同的key值对应同一个哈希函数,得到相同的内存地址。(链表)
1、存在重复元素
// 输入: [1,2,3,1] 输出: true
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
sort(nums.begin(),nums.end());
for(int i = 0;i < nums.size()-1; i++) {
if(nums[i] == nums[i+1]) {
return true;
}
}
return false;
}
};
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
unordered_set<int> s;
for(int x: nums) {
if(s.find(x) != s.end()) //find这个函数,找不到会返回end(); != :找到这个元素了
return true;
s.insert(x);
}
return false;
}
};
2、找不同
//输入:s = "abcd", t = "abcde" 输出:"e"
class Solution {
public:
char findTheDifference(string s, string t) {
vector<int> v(26,0);
for(char x : s) {
v[x-'a']++;
}
for(char x : t) {
v[x- 'a']--;
if(v[x - 'a'] < 0) {
return x;
}
}
return ' ';
}
};
集合set:
1、检查某个元素是否存在
2、重复元素
1、设计哈希集合
class MyHashSet {
public:
/** Initialize your data structure here. */
MyHashSet() {
map.resize(1000010,0);
}
void add(int key) {
map[key] = true;
}
void remove(int key) {
map[key] = false;
}
/** Returns true if this set contains the specified element */
bool contains(int key) {
return map[key];
}
private:
vector<bool> map;
};
树:
//二叉树定义:
struct TreeNode {
int val;
TreeNode *right;
TreeNode *left;
TreeNode(int x) :val(x), left(NULL) ,right(NULL) {} //构造函数
};
1、递归法 前中后遍历
//前中后遍历:
clss Solution {
public:
void traversal(TreeNode *cur,vector<int> &vec) { //前序遍历
if(cur == NULL) return ;
vec.push_back(cur->val);
traversal(cur->left,vec);
traversal(cur->right,vec);
}
void travesal(TreeNode *cur,vector<int> &vec) { //中序遍历
if(cur == NULL) return;
travesal(cur->left,vec);
vec.push_back(cur->val);
travesal(cur->right,vec);
}
void travesal(TreeNode *cur,vector<int> &vec) { //后序遍历
if(cur == NULL) return;
travesal(cur->left,vec);
travesal(cur->right,vec);
vec.push_back(cur->val);
}
vector<int> preorderTraverasl(TreeNode * root) {
vector<int> result;
travelsal(root,result);
return result;
}
};
2、用栈实现二叉树遍历
//用栈实现二叉树遍历
//栈先进后出 队列先进先出
//前序遍历是中左右,每次先处理的是中间节点,那么先将跟节点放入栈中,然后将右孩子加入栈,再加入左孩子。
class solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
stack<TreeNode*> st; //定义一个栈,每个节点的类型为 树节点指针
vector<int> result;
if(root == NULL ) return result;
st.push(root); // 先将根节点入栈
//一直执行,直到栈为空,然后将左节点出栈,然后右节点。
while(!st.empty()) {
TreeNode* node = st.top(); //定义一个栈顶指针
st.pop(); //弹出根节点
result.push_back(node->val); //将结果存在vector容器中
if(node->right) st.push_back(node->right); //右 (空节点不如栈)
if(node->left) st.push_back(node->left); //左
}
return result;
}
};
//中序遍历(迭代法)
//处理:将元素放到result数组中
//遍历节点 指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
//中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点
class solution {
public:
vector<int> inorderTraversal(TreeNode *root) {
vector<int> result;
stack<TreeNode*> st;
TreeNode* cur =root; //curr定义为将要入栈的结点,初始化为root
while(cur != NULL || !st.empty()) {
if(cur != NULL) { //指针访问节点,访问到最底层
st.push(cur); //将访问的节点放进栈
cur = cur->left;
}
else {
cur = st.top(); //从栈弹出数据,就是要放进数组的数据
st.pop();
result.push_back(cur->val); //中
cur = cur ->right; //右
}
}
return result;
}
};
//后序遍历
if (node->left) st.push(node->left); // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
if (node->right) st.push(node->right); // 空节点不入栈
reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
return result;
堆(heap):
删除节点:只能删除堆顶元素, 将最后一个元素喝堆顶元素就行交换,然后重新构造大小顶堆。
1、前K个高频元素
class Solution {
public:
static bool compare( pair<string, int>& s1, pair<string, int>& s2) {
// 频率相等,按字母排序
if(s1.second == s2.second) return s1.first < s2.first;
// 按照频率排序
else return s1.second > s2.second;
}
vector<string> topKFrequent(vector<string>& words, int k) {
//用哈希表进行查找
//统计出现频率
unordered_map<string,int> m;
for(string word : words) {
m[word] ++;
}
//将map表放进vector容器中 进行排序
vector<pair<string,int>> v(m.begin(),m.end());
sort(v.begin(),v.end(), compare);
vector<string> ans; //记录输入
for(int i = 0; i < k; i++ ) {
ans.push_back(v[i].first);
}
return ans;
}
};