刷题心得:
- for循环中++i省去了对内存的操作,比i++的性能好;
- 栈:
#include<stack>
stack<type> s
push pop top empty size
- 队列:
#include<queue>
queue<type> q
push pop front back empty size
- 散列表:
#include<map>
map<type,type> m
- 拷贝
for(auto x:range)
修改for(auto &&x:range)
只读for(const auto &x:range)
题目: i=i>>1
右移1位i=i<<1
左移1位
文章目录
数组
有多少小于当前数字的数字
方法一:暴力法
var smallerNumbersThanCurrent = function(nums) {
var newnums=new Array();
for(var i = 0;i<nums.length;++i){
var count=0;
for(var j = 0;j<nums.length;++j){
if (nums[i]>nums[j]){
count++;
newnums[i]=count;
}
else{
newnums[i]=count;
}
}
}
return newnums;
};
方法二:数组拷贝+数组排序+indexOf(获取字符串中首次出现的位置)
var smallerNumbersThanCurrent = function(nums) {
//数组拷贝
let nums1 = []
let nums2 = [].concat(nums)
//数组排序
let nums3 = nums.sort((a,b) => {return a-b})
nums2.forEach(item => {
nums1.push(nums3.indexOf(item))
})
return nums1
};
柠檬水找零[5,10,15]
Tip:使用哈希表 统计元素个数
class Solution {
public:
bool lemonadeChange(vector<int>& bills){
map<int,int> m;//创建哈希表
for (int i = 0; i < bills.size(); i++) {
m[bills[i]]++;//统计每个元素的个数
if (bills[i] == 10) {//有一个10就必须减一个5
m[5]--;
}
if (bills[i] == 20) {//有一个20可以减去1个10和1个5或3个5
if (m[10] > 0) {
m[10]--;
m[5]--;
}
else{
m[5] = m[5] - 3;
}
}
if (m[5] < 0) {
return false;
}
}
return true;
}
};
最大连续子序和
动态规划:f(i)=max{f(i-1)+nums[i],nums[i]}
class Solution {
public:
int maxSubArray(vector<int>& nums)
{
int max_number = nums[0];
int pre_number = 0;
for(int i=0;i<nums.size();++i)
{
pre_number = max(pre_number+nums[i],nums[i]);
max_number = max(max_number,pre_number);
}
return max_number;
}
};
跳跃游戏
class Solution {
public:
bool canJump(vector<int>& nums) {
int temp=0;
for (int i=0; i<nums.size(); ++i) {
if (i<=temp)
{
temp=max(temp, i+nums[i]);//temp记录当前更新的位置
if (temp>=nums.size()-1) {
return true;
}
}
}
return false;
}
};
两数之和
- 无序
暴力法
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> nums;
for(int i=0;i<numbers.size();++i)
{
for (int j=i+1; j<numbers.size(); ++j) {
if(numbers[i]+numbers[j]==target){
nums.push_back(i);
nums.push_back(j);
}
}
}
return nums;
}
};
int main() {
int k;
vector<int> obj;
vector<int> newobj;
while (cin >> k) {
obj.push_back(k);
if (cin.get() == '\n') break;
}
cin >> k;
newobj = twoSum(obj, k);
cout << "[" << newobj[0] << "," << newobj[1] << "]" << endl;
return 0;
}
- 有序
暴力法O(n2):溢出
二分查找O(nlogn)
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
for (int i=0; i<numbers.size(); ++i) {
int low=i+1,high=numbers.size()-1;
while (low<=high) {
int mid=(high-low)/2+low;
if (numbers[mid]+numbers[i]==target) {
return {i+1,mid+1};
}
else if(numbers[mid]+numbers[i]<target){
low=mid+1;
}
else{
high=mid-1;
}
}
}
return {-1,-1};
}
};
双指针O(n)
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int low=0,high=numbers.size()-1;
while(low<=high){
if (numbers[low]+numbers[high]==target) {
return {low+1,high+1};
}
else if(numbers[low]+numbers[high]>target){
--high;
}
else{
++low;
}
}
return {-1,-1};
}
};
三数之和
vector<vector<int>> threeSumTarget(vector<int>& nums,int num) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
for (int first = 0; first < n; ++first) {
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
int third = n - 1;
int target = num-nums[first];
for (int second = first + 1; second < n; ++second) {
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
while (second < third && nums[second] + nums[third] > target) {
--third;
}
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
ans.push_back({ nums[first], nums[second], nums[third] });
}
}
}
return ans;
}
int main() {
vector<int> nums = { -1, 0, 1, 2, -1, -4 };
vector<vector<int>> res;
res = threeSumTarget(nums,0);
cout << "[";
for (int i = 0; i < res.size(); i++) {
cout << "[" << res[i][0]<<"," << res[i][1] << "," << res[i][2] <<"]";
}
cout << "]";
return 0;
}
数组中的k个最强值
题目:给你一个整数数组 arr 和一个整数 k 。设 m 为数组的中位数,只要满足下述两个前提之一,就可以判定 arr[i] 的值比 arr[j] 的值更强: |arr[i] - m| > |arr[j] - m|,|arr[i] - m| == |arr[j] - m|,且 arr[i] > arr[j]返回由数组中最强的 k 个值组成的列表。
双指针
vector<int> getStrongest(vector<int>& arr, int k) {
vector<int> newarr;
sort(arr.begin(), arr.end());
int low=0;
int mid=(arr.size()-1)/2;
int high=arr.size()-1;
for (int i=0; i<k; ++i) {
if (arr[mid]-arr[low]>arr[high]-arr[mid]) {
newarr.push_back(arr[low]);
++low;
}
else{
newarr.push_back(arr[high]);
--high;
}
}
return newarr;
重塑矩阵(二维数组)
class Solution {
public:
vector<vector<int>> matrixReshape(vector<vector<int>>& nums, int r, int c) {
if (nums.empty() || nums[0].empty()) return nums;
//新建r行c列初值为0的矩阵
vector<vector<int> > newnums(r, vector<int>(c, 0));
int N = nums.size() * nums[0].size();
if (N % r != 0 || N / r != c) return nums;
for (int i = 0; i < N; ++i) {
//依次遍历数组并且替换每个位置的值
newnums[i / c][i % c] = nums[i / nums[0].size()][i % nums[0].size()];
}
return newnums;
}
};
整数反转
int reverse(int x) {
long temp=0, y=0;
if (x == 0) return 0;
while (x != 0) {
temp = x % 10;
y = y * 10 + temp;
x = x / 10;
}
if (y<=INT_MIN || y>=INT_MAX) {
return 0;
}
return y;
}
int main() {
int k, result;
cin >> k;
result = reverse(k);
cout << result << endl;
return 0;
}
三角形最小路径和
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
vector<int> dp(n+1,0);
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < triangle[i].size(); j++) {
dp[j] = min(dp[j], dp[j + 1]) + triangle[i][j];
}
}
return dp[0];
}
股票买卖
//暴力法,超时
int maxProfit1(vector<int>& prices) {
int max_num = 0;
for (int i = 0; i < prices.size() - 1; i++) {
for (int j = prices.size() - 1; j > i; j--) {
max_num = max(prices[j] - prices[i], max_num);
}
}
return max_num;
}
//寻找最低价格股票
int maxProfit2(vector<int>& prices) {
int max_num = 0;
int min_price = INT_MAX;
for (int i = 0; i < prices.size(); i++) {
min_price = min(min_price, prices[i]);
max_num = max(prices[i] - min_price, max_num);
}
return max_num;
}
字符串
1、最长回文子串
string longestPalindrome(string s) {
int n = s.size();
if (n == 1) return s;
int start = 0;
int max = 1;
vector<vector<int>> dp(n, vector<int>(n));
for (int i = 0; i < n; i++) {
dp[i][i] = 1;
if (i < n - 1 && s[i] == s[i + 1]) {
dp[i][i + 1] = 1;
max = 2;
start = i;
}
}
for (int l = 3; l <= n; l++)
{
for (int i = 0; i + l - 1 < n; i++)
{
int j = l + i - 1;
if (s[i] == s[j] && dp[i + 1][j - 1] == 1)//状态转移
{
dp[i][j] = 1;
start = i;
max = l;
}
}
}
return s.substr(start, max);
}
int main() {
string s = "abbd";
cout << longestPalindrome(s) << endl;
return 0;
}
2、无重复字符的最长子串
滑动窗口
int lengthOfLongestSubstring(string s) {
set<int> occ;
int length = 0;
int j = -1;
for (int i = 0; i < s.size(); i++) {
if (i != 0) occ.erase(s[i-1]);//移动1位,删除左边字符
while (j + 1 < s.size()&&!occ.count(s[j+1])) {
occ.insert(s[j + 1]);
j++;
}
length = max(length, j - i + 1);
}
return length;
}
int main() {
int length;
string s;
cin >> s;
length = lengthOfLongestSubstring(s);
cout << length << endl;
return 0;
}
3、Z 字形变换
string convert(string s, int numRows) {
if (numRows == 1) return s;
vector<string> nums(numRows);//定义字符串型数组,长度是numRows
int row = 0;
bool down = false;//标志
for (int i = 0; i < s.size(); i++) {
nums[row] += s[i];
if (row == 0 || row == numRows - 1) {
down = !down;
}
row = row + (down ? 1 : -1);
}
string str;
for (int i = 0; i < nums.size();i++) {
str += nums[i];
}
return str;
}
int main() {
int length;
string str,newstr;
cin >> str;
cin >> length;
newstr = convert(str,length);
cout << newstr << endl;
return 0;
}
字符串相加
string addStrings(string num1, string num2) {
string str="";
int add = 0;//进位标志
int i = num1.size()-1, j = num2.size()-1;
while (i >=0 || j >=0|| add != 0) {
//整数转字符
int x = i >= 0 ? num1[i] - '0' : 0;
int y = j >= 0 ? num2[j] - '0' : 0;
int result = x + y + add;
str.push_back('0' + result % 10);
add = result / 10;
i--;
j--;
}
reverse(str.begin(), str.end());
return str;
}
int main() {
string str="";
string num1 = "123";
string num2 = "456";
str = addStrings(num1, num2);
cout << "'" << str << "'" << endl;
return 0;
}
链表
1、给定一个链表,判断链表中是否有环
方法一:双指针——快慢指针
class Solution1 {
public:
bool hasCycle(ListNode *head)
{
ListNode* fast=head;
ListNode* slow=head;
if (head==nullptr) return false;
while (fast!=nullptr&&fast->next!=nullptr)//此条件重要
{
fast=fast->next->next;//快指针
slow=slow->next;//慢指针
if (fast==slow)
{
return true;
}
}
return false;
}
};
方法二:哈希表——哈希表节点出现的次数
class Solution2 {
public:
bool hasCycle(ListNode *head)
{
map<ListNode*,int> m;//哈希表
while (head!=nullptr)
{
m[head]++;//存放链表中的所有节点
if (m[head]>1) {//如果相同的节点出现的次数超过一次
return true;
}
head = head->next;
}
return false;
}
};
2、反转链表
非递归:新建链表存放
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* p=head;//添加到新链表的节点
ListNode* q=nullptr;//新链表的最后
while (p!=nullptr) {
ListNode* tmp=p->next;//保存p->next
p->next=q;
q=p;
p=tmp;
}
return q;
}
};
递归
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==nullptr||head->next==nullptr)
return head;//递归的结束条件
ListNode* p=reverseList(head->next);
head->next->next=head;//类似于一个单循环链表
head->next=nullptr;
return p;
}
};
int main() {
ListNode* head=new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
ListNode* headNew = reverseList(head);
while (headNew != NULL) {
cout << headNew->val << " ";
headNew = headNew->next;
}
return 0;
}
3、k个一组翻转链表
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* newNode = new ListNode(-1);
ListNode* prev = newNode;
stack<ListNode*> st;
while (true) {
int count = 0;
ListNode* temp = head;
while (temp != NULL && count < k) {
st.push(temp);
temp = temp->next;
count++;
}
if (count != k) break;
while (!st.empty()) {
prev->next = st.top();
st.pop();
prev = prev->next;
}
prev->next = temp;
head = temp;
}
return newNode->next;
}
int main() {
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next= new ListNode(3);
head->next->next->next = new ListNode(4);
head->next->next->next->next = new ListNode(5);
ListNode* newhead = reverseKGroup(head,3);
while (newhead != NULL) {
cout << newhead->val << " ";
newhead = newhead->next;
}
return 0;
}
4、两数相加
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* l3 = new ListNode(0);
ListNode* temp = l3;//临时结点
int add = 0;//进位
while (l1 || l2) {
int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + add;
temp->next = new ListNode(sum % 10);
temp = temp->next;
add = sum >= 10 ? 1 : 0;
if(l1) l1 = l1->next;
if(l2) l2 = l2->next;
}
while (add > 0) {
temp->next = new ListNode(add);
}
return l3->next;
}
int main() {
ListNode* l1 = new ListNode(2);
l1->next = new ListNode(4);
l1->next->next = new ListNode(3);
ListNode* l2 = new ListNode(5);
l2->next = new ListNode(6);
l2->next->next = new ListNode(4);
ListNode* result = nullptr;
result = addTwoNumbers(l1, l2);
while (result != nullptr) {
cout << result->val << "->";
result = result->next;
}
return 0;
}
二叉树
1、找树左下角的值
方法一:递归
class Solution1 {
public:
int result = 0,MaxDepth = 0;
int findBottomLeftValue(TreeNode* root) {
findMaxDepth(root,1);
return result;
}
void findMaxDepth(TreeNode* root,int depth){
if(root == nullptr) return;
if(depth>MaxDepth){
MaxDepth = depth;
result = root->val;
}
findMaxDepth(root->left,depth+1);
findMaxDepth(root->right,depth+1);
}
};
方法二:层次遍历
class Solution2 {
public:
int findBottomLeftValue(TreeNode* root) {
int result = 0;
queue<TreeNode*> myQueue;//创建空队列
myQueue.push(root);
while (!myQueue.empty()) {
result = myQueue.front()->val;
int tempSize = myQueue.size();
for(int i = 0;i < tempSize;i++){//将队列中的元素依次出队
TreeNode* p = myQueue.front();
myQueue.pop();
if (p->left!=nullptr) {
myQueue.push(p->left);
}
if (p->right!=nullptr) {
myQueue.push(p->right);
}
}
}
return result;
}
};
2、在每个树行中找最大值
方法一:层次遍历
class Solution1 {
public:
vector<int> nums;
vector<int> largestValues(TreeNode* root) {
if (root ==nullptr) return nums;//返回值必须是数组
queue<TreeNode*> myQueue;
myQueue.push(root);
while (!myQueue.empty()) {
int max_num= INT_MIN;
int len = myQueue.size();//每一层的节点个数
for (int i = 0; i<len; i++) {//一层一层进行比较
TreeNode* p = myQueue.front();//队头指针
max_num = max(p->val, max_num);
if (p->left!=nullptr) {
myQueue.push(p->left);
}
if (p->right!=nullptr) {
myQueue.push(p->right);
}
myQueue.pop();//队头元素出队
}
nums.push_back(max_num);
}
return nums;
}
};
方法二:深度遍历
class Solution1 {
public:
vector<int> nums;
int height = 0;
vector<int> largestValues(TreeNode* root) {
compareNumber(root,height);
return nums;
}
void compareNumber(TreeNode* root,int height){
if (root == nullptr) return;
if (nums.size() < height+1) {
nums.push_back(root->val);//新的位置上插入元素
}
else{
nums[height]=max(root->val, nums[height]);//相同的位置上元素比较大小
}
if (root->left!=nullptr) {
compareNumber(root->left, height+1);
}
if (root->right!=nullptr) {
compareNumber(root->right, height+1);
}
}
};
3、先序遍历
递归
class Solution1 {
public:
vector<int> nums;
void preorder(TreeNode* root){
if (root==nullptr) return;
nums.push_back(root->val);
preorder(root->left);
preorder(root->right);
}
vector<int> preorderTraversal(TreeNode* root) {
preorder(root);
return nums;
}
};
非递归(栈+数组)
class Solution2 {
public:
vector<int> preorderTraversal(TreeNode* root) {
if(root==nullptr) return {};
stack<TreeNode*> s;
vector<int> ans;
TreeNode* p=root;
while (!s.empty()||p) {
while (p) {
s.push(p);
ans.push_back(p->val);
p=p->left;
}
TreeNode* q=s.top();
s.pop();
q=p->right;
}
return ans;
}
};
4、中序遍历
递归
class Solution1 {
public:
vector<int> nums;
void inorder(TreeNode* root){
if (root==nullptr) return;
inorder(root->left);
nums.push_back(root->val);
inorder(root->right);
}
vector<int> inorderTraversal(TreeNode* root) {
inorder(root);
return nums;
}
};
非递归
class Solution2 {
public:
vector<int> inorderTraversal(TreeNode* root) {
if(root == NULL) return {};
stack<TreeNode*> s;
vector<int> ans;
TreeNode* p = root;
while(!s.empty() || p){
while(p){
s.push(p);
p = p->left;
}
TreeNode* q = s.top();
s.pop();
ans.push_back(q->val);
p = q->right;
}
return ans;
}
};
5、后序遍历
递归
class Solution1 {
public:
vector<int> nums;
void postorder(TreeNode* root){
if (root==nullptr) return;
postorder(root->left);
postorder(root->right);
nums.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
postorder(root);
return nums;
}
};
非递归
class Solution2 {
public:
vector<int> postorderTraversal(TreeNode* root) {
if(root==nullptr) return {};
stack<TreeNode*> s;
vector<int> ans;
TreeNode* p=root;
while (!s.empty()||p) {
while (p) {
s.push(p);
ans.push_back(p->val);
p=p->right;
}
TreeNode* q=s.top();
s.pop();
p=q->left;
}
reverse(ans.begin(), ans.end());
return ans;
}
};
6、层次遍历(队列+数组)
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;
if (root==nullptr) return {};
queue<TreeNode*> que;
que.push(root);
while (!que.empty()) {
int size=que.size();
ans.push_back(vector<int>());
for(int i=0;i<size;++i){
TreeNode* p=que.front();
que.pop();
ans.back().push_back(p->val);
if (p->left!=nullptr) que.push(p->left);
if (p->right!=nullptr) que.push(p->right);
}
}
return ans;
}
};
二叉树的锯齿形层次遍历
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> ans;
if (root == NULL) return {};
queue<TreeNode*> que;
que.push(root);
int level = 0;//层数
while (!que.empty())
{
vector<int> temp;
int count = que.size();//当前层的元素个数
while (count--)
{
TreeNode* p = que.front();
que.pop();
if (level % 2 == 0)
temp.push_back(p->val);
else
temp.insert(temp.begin(), p->val);
if (p->left) que.push(p->left);
if (p->right) que.push(p->right);
}
level++;
ans.push_back(temp);
}
return ans;
}
int main() {
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(9);
root->right = new TreeNode(20);
root->right->left = new TreeNode(15);
root->right->right = new TreeNode(7);
vector<vector<int>> ans;
ans = zigzagLevelOrder(root);
for (int i = 0; i < ans.size(); i++) {
for(int j=0;j<ans[i].size();j++){
cout << ans[i][j] << ",";
}
}
return 0;
}