Leetcode刷题

刷题心得:

  • 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值