算法记录 & 牛客网 & leetcode刷题记录

解题思路

从最简单的case开始想,一般能找到规律。

如果从最简单的case不能找到思路,那么一般人不会,也不用死扎着这道题。


STL容器

map<type,type2> :有序的,如果不指定排序,最后一个元素最大
unordered_map:无序的
set:有序的
unordered_set:无序的
vector
priority_queue <int,vector,greater > q:从小到大排列
priority_queue <int,vector,less >q:从大到小排列

常用算法模板

堆排序

小顶堆:每次都把最大的调整到根部,最后把最大的放在数组末尾,最终形成的堆根部是最小的
大顶堆:每次都把最小的调整到根部,最后把最小的放在数组末尾,最终形成的堆根部是最大的

在优先队列里,

//小顶堆,top的时候返回元素最小的那个
priority_queue <int,vector<int>,greater<int> > q;
//大顶堆,top的时候返回元素最大的那个
priority_queue <int,vector<int>,less<int> >q;
``


堆排序每次调整成大顶/小顶堆后,把堆顶元素放到数组末尾,然后继续调整大顶/小顶堆
```cpp
class HeapSort {
public:
	void heapSort(vector<int>& arr) {
		if (arr.size() == 0) {
			return;
		}
		int len = arr.size();
		// 构建大顶堆,这里其实就是把待排序序列,变成一个大顶堆结构的数组
		buildMaxHeap(arr, len);
 
		// 交换堆顶和当前末尾的节点,重置大顶堆
		for (int i = len - 1; i > 0; i--) {
			swap(arr, 0, i);
			len--;
			heapify(arr, 0, len);
		}
	}
 
	void buildMaxHeap(vector<int>& arr, int len) {
		// 从最后一个非叶节点开始向前遍历,调整节点性质,使之成为大顶堆
		for (int i = (int)floor(len / 2) - 1; i >= 0; i--) {
			heapify(arr, i, len);
		}
	}
 
	void heapify(vector<int>& arr, int i, int len) {
		// 先根据堆性质,找出它左右节点的索引
		int left = 2 * i + 1;
		int right = 2 * i + 2;
		// 默认当前节点(父节点)是最大值。
		int largestIndex = i;
		if (left < len && arr[left] > arr[largestIndex]) {
			// 如果有左节点,并且左节点的值更大,更新最大值的索引
			largestIndex = left;
		}
		if (right < len && arr[right] > arr[largestIndex]) {
			// 如果有右节点,并且右节点的值更大,更新最大值的索引
			largestIndex = right;
		}
 
		if (largestIndex != i) {
			// 如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点值互换
			swap(arr, i, largestIndex);
			// 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。
			heapify(arr, largestIndex, len);
		}
	}
 
	void swap (vector<int>& arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
};

插入排序

插入排序其实是冒泡排序的反向,插入排序从数组第二个元素开始,每加入一个元素,都将其和前面已有的元素进行比较,然后不断调整位置。

void insertionSort(vector<int> & data) {
	for (int i = 1; i < data.size(); i++) {
		for (int j = i; j >= 1; j--) {
			if (data[j] < data[j - 1]) {
				int tmp = data[j];
				data[j] = data[j - 1];
				data[j - 1] = tmp;
			}
		}
	}
	return;
}

快速排序

原理:每次随机将数组中的一个数,放到他指定的排序后的位置。
比如,把一个数A,放到数组的位置i,那么[0,i-1]的位置都是比A小的数,[i+1,size-1]都是比A大的数

class Solution {
public:
    void qsort(vector<int>& nums,int start,int end,int k){
    int size=nums.size();
    int i=start,j=end,base=nums[start];
    if(size<=0) return;
    
    
    while(i<j){
        while(nums[j]<=base && i<j){
            j--;    
        }
        
        if(i<j) nums[i]=nums[j];
        
        while(nums[i]>=base && i<j) i++;
        
        if(i<j) nums[j]=nums[i];
     }
    
     
     nums[i]=base;
    
    if(i+1>k) qsort(nums,start,i-1,k);
    else if(i+1==k) return ;
    else qsort(nums,i+1,end,k);
}
    
    int findKthLargest(vector<int>& nums, int k) {
        int size=nums.size();
        qsort(nums,0,size-1,k);
        return nums[k-1];
    }
    
    
    
};

BFS层序遍历

二叉树的层序遍历

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(root == nullptr){
            return res;
        }

        queue<TreeNode*> q;

        q.push(root);

        while(!q.empty()){
            int level_size = q.size();
            vector<int> v;

            while(level_size--){
                TreeNode* tmp_node = q.front();
                if (!(tmp_node->left== nullptr)){
                    q.push(tmp_node->left);
                }
                if(!(tmp_node->right == nullptr)){
                    q.push(tmp_node->right);
                }
                q.pop();
                v.push_back(tmp_node->val);
            } 
            
            res.push_back(v);
        }
        return res;
    }
};

二叉树

JZ55 二叉树的深度

关键词:二叉树、深度优先遍历、递归


自己写的笨蛋方法:

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    int max_depth = 0;
    int now_depth = 0;
    int TreeDepth(TreeNode* pRoot) {
        if(pRoot == NULL){
            return max_depth;
        }
        this->now_depth++;
        if(now_depth>max_depth){
            max_depth=now_depth;
        }
        this->TreeDepth(pRoot->left);
        this->TreeDepth(pRoot->right);
        this->now_depth--;
        return max_depth;
    }
};

优秀解答:

  1. 递归解法
class Solution {
public:
	int TreeDepth(TreeNode* pRoot){
	    if(!pRoot) return 0 ;
            return max(1+TreeDepth(pRoot->left), 1+TreeDepth(pRoot->right));
	}
};
  1. BFS解法
import java.util.Queue;
import java.util.LinkedList;

public class Solution {
	public int TreeDepth(TreeNode pRoot)
    {
    	if(pRoot == null){
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(pRoot);
        int depth = 0, count = 0, nextCount = 1;
        while(queue.size()!=0){
            TreeNode top = queue.poll();
            count++;
            if(top.left != null){
                queue.add(top.left);
            }
            if(top.right != null){
                queue.add(top.right);
            }
            if(count == nextCount){
                nextCount = queue.size();
                count = 0;
                depth++;
            }
        }
        return depth;
    }
}

BST(binary search tree)的公共祖先

BST的公共祖先


回溯

其实回溯就是递归

解题的时候,如果遇到给的函数参数不够,可以另自己起一个函数

JZ12 矩阵中的路径

我的答案

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param matrix char字符型vector<vector<>> 
     * @param word string字符串 
     * @return bool布尔型
     */
    int now=0;
    bool flag = false;
    stack<int*> s;
    vector<vector<bool>> v;
    bool hasPath(vector<vector<char> >& matrix, string word) {
        // write code here
        if(matrix.size()==0 || word.size()==0 || matrix[0].size()==0){
            return false;
        }
        
        if(now == 0){
            v.resize(matrix.size(), vector<bool>(matrix[0].size()));
        }
        
        if(word[now] == '\0'){
            flag=true;
            return flag;
        }
        if(now ==0){
            for(int i = 0;i<matrix.size();i++){
                for(int j=0; j<matrix[0].size();j++){
                    if(flag){
                        break;
                    }
                    if(matrix[i][j]==word[now]){
                        now++;
                        int arr[2]={i,j};
                        s.push(arr);
                        v[i][j] = true;
                        if(hasPath(matrix, word)){
                             return flag;  
                        }
                        s.pop();
                        now--;
                        v[i][j]=false;
                    }
                }
            }
        }
        else{
            int* arr = s.top();
            int i = arr[0];
            int j = arr[1];
            
            if(i!=0 &&  matrix[i-1][j] == word[now] && v[i-1][j]!=true){
                now++;
                int tmp[2] = {i-1, j};
                s.push(tmp);
                v[i-1][j]= true;
                if(hasPath(matrix, word)){
                    return flag;
                }
                v[i-1][j]= false;
                s.pop();
                now--;
            }
            if(i!=matrix.size()-1 &&  matrix[i+1][j] == word[now] && v[i+1][j]!=true){
                now++;
                int tmp[2] = {i+1, j};
                s.push(tmp);
                v[i+1][j]= true;
                if(hasPath(matrix, word)){
                    return flag;
                }
                v[i+1][j]= false;
                s.pop();
                now--;
            }
            if(j!=matrix[0].size()-1 &&  matrix[i][j+1] == word[now] && v[i][j+1]!=true){
                now++;
                int tmp[2] = {i, j+1};
                s.push(tmp);
                v[i][j+1]= true;
                if(hasPath(matrix, word)){
                    return flag;
                }
                v[i][j+1]= false;
                s.pop();
                now--;
            }
            if(j!=0 &&  matrix[i][j-1] == word[now] && v[i][j-1]!=true){
                now++;
                int tmp[2] = {i, j-1};
                s.push(tmp);
                v[i][j-1]= true;
                if(hasPath(matrix, word)){
                    return flag;
                }
                v[i][j-1]= false;
                s.pop();
                now--;
            }
            
            
        }
        return flag;
    }
};

高分答案

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param matrix char字符型二维数组 
     * @param word string字符串 
     * @return bool布尔型
     */
    public boolean hasPath (char[][] board, String word) {
        // write code here
              int  length1=board[0].length;//列数
      int  length2=board.length;//行数
        for(int i =0; i<length2;i++){
            for(int j=0;j<length1;j++){
                if(board[i][j]==word.charAt(0))
                 if(dfs(board,i,j,word,0))
                    return true;
                    
               
            }
        }
        return false;
    }

    public boolean dfs(char[][] board,int i, int j, String word, int u){
      int  length1=board[0].length;//列数
      int  length2=board.length;//行数
        //失败:先判断边界值
        if(i<0||i>=length2||j<0||j>=length1||board[i][j]!=word.charAt(u)){
            return false;
        }
        //成功:遍历到最后一个
        if(u==word.length()-1)
            return true;
        //覆盖原来防止重复
        char temp = board[i][j];
        board[i][j]= '#';
        //递归调用
        boolean res = dfs(board,i-1,j,word,u+1) || dfs(board,i+1,j,word,u+1) || dfs(board,i,j-1,word,u+1)
        || dfs(board,i,j+1,word,u+1) ;
        //递归结束
        board[i][j]= temp;
        return res;
        
    }
}

总结:
回溯刚开始都要判断结束 && 判断边界 && 判断条件

接下来再调用自己。

有没有走过可以先覆盖原来的,之后回溯出来的时候再写回原来的
(这样就避免了还要自己初始化一个数组判断是否走过)

二分查找、排序

二分诀窍:

  1. 找到二分开始的位置
  2. 找到二分前进的方向

关于左开右闭,左闭右开,左闭右闭
【玩转二分查找Ⅰ】左闭右闭型,左开右闭型,左闭右开型(动图演绎)

核心是,中间值的取法不同 以及 while循环内部的判断方式不同


Leetcode-148 排序链表

leetcode-排序列表题目详情
总结:使用归并排序
链表找到中间位置:是用一个快指针,一个慢指针。

卡了很久的一个点:

if(first_pointer == nullptr) 
	return second_pointer 
else
	return first_pointer

这是错误的,因为忽略了 first_pointer和second_pointer都有值的情况


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == nullptr || head->next==nullptr){
            return head;
        } 

        ListNode* first_pointer=head;
        ListNode* second_pointer=head->next;
        
        // 找到中间的位置
        while((second_pointer!=nullptr) && (second_pointer->next!=nullptr) ){
            first_pointer = first_pointer->next;
            second_pointer = second_pointer->next;
            if(second_pointer->next != nullptr){
                second_pointer = second_pointer->next;
            }
        }

        
        ListNode* next_pointer = first_pointer->next;
        first_pointer->next =nullptr;
        head = sortList(head);
        next_pointer = sortList(next_pointer);
        
        return Merge(head,next_pointer);
    }

    ListNode* Merge(ListNode* first_pointer, ListNode* second_pointer){
        ListNode* head;
        ListNode* tick;
        if(first_pointer == nullptr){
            return second_pointer;
        }
        if(second_pointer == nullptr){
            return first_pointer;
        }

        if(first_pointer->val < second_pointer->val){
            head=first_pointer;
            tick=first_pointer;
            first_pointer = first_pointer->next;
        }
        else{
            head=second_pointer;
            tick=second_pointer;
            second_pointer = second_pointer->next;
        }

        while(first_pointer!=nullptr && second_pointer!=nullptr){
            if(first_pointer->val < second_pointer->val){
                tick->next= first_pointer;
                first_pointer = first_pointer->next;
                tick = tick->next;
            }
            else{
                tick->next = second_pointer;
                second_pointer = second_pointer->next;
                tick = tick->next;
            }
        }

        if(first_pointer==nullptr){
            tick->next =second_pointer;

        }
        else{
            tick->next=first_pointer;
        }

        return head;

    }

};

BM18 二维数组中的查找

矩阵中,行和列都是递增,那么可以找左下,或者右上的元素开始。
复杂度:O(n+m)

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int r = array.size();
        if(r == 0){
            return false;
        }
        int col = array[0].size();
        if(col == 0){
            return false;
        }
        int i = 0, j =col-1;
        
        while(i<=r-1 && j>=0 ){
            if(array[i][j] == target){
                return true;
            }
            else if(array[i][j] >target){
                j--;
            }
            else if(array[i][j]<target){
                i++;
            }
             
        }
            
        return false;
    }
};

BM19寻找峰值

复杂度O(logn)
思想: 上坡一定有波峰,下坡不一定有波峰

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int findPeakElement(vector<int>& nums) {
        // write code here
        int right = nums.size()-1;
        int left = 0;
        while(left<right){
            int mid = (left+right)/2;
            if(nums[mid]>nums[mid+1]){
                right = mid;
            }
            else{
                left = mid+1;
            }
        }
        return right;
    }
};

295. 数据流的中位数

295.数据流的中位数

思想: 维护两个堆,一个大顶堆(堆顶是最大的元素),一个是小顶堆(堆顶是最小的元素)。

每个堆都存储一半的元素,大顶堆的元素总是小于等于小顶堆的元素。

那么中位数就可以通过大顶堆堆顶和小顶堆堆顶元素来判断。

class MedianFinder {
public:
	// 小顶堆,堆顶是最小的元素
    priority_queue<int, vector<int>, greater<int>> big;
	// 大顶堆,堆顶是最大的元素
    priority_queue<int, vector<int>, less<int>> small;
    MedianFinder() {
    }
    
    void addNum(int num) {
        big.push(num);
        
        small.push(big.top());
        big.pop();
        if(small.size()>big.size()){
            big.push(small.top());
            small.pop();
        }
    }
    
    double findMedian() {
        if(big.size() == small.size()){
            return (big.top() +small.top())/2.0; 
        }
        else{
            return big.top();
        }
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */

Sort a nearly sorted (or K sorted) array

题目描述:对一个元素正确位置,离自己至多K个距离的数组,进行排序
提示:堆排序,建立一个k+1大小的堆(因为K+1个堆里,肯定最顶上那个是排序好的,把他取出来放在正确的位置即可)

答案-Sort a nearly sorted (or K sorted) array

动态规划

所以在DP的实践中很重要的就是递推关系边界条件
1. 边界条件
所谓边界条件就是最简单的情况。
2. 递推关系
所谓递推关系就是如果你已经知道这么多,再多给你一个,你怎么得到。
(状态转移方程)

状态定义、状态转移方程


DP5 连续子数组最大和

状态定义: array[i] 表示数组连续到下标为i为止的连续数组最大和
(注意区别于整个数组的连续数组最大和, 或者说 array[i]代表以第 i 个数结尾的子数组最大连续和)
状态转移方程: state[i] = max(state[i-1]+array[i], array[i])
因为最终求的是整个数组的最大值,所以要使用max_num来存储最大值

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin>>n;
    vector<int> array(n, 0);
    vector<int> state(n,INT_MIN);
    
    cin>>array[0];
    state[0] = array[0];
    int max_num = array[0];
    
    for(int i=1;i<n;i++){
        cin>>array[i];
        state[i] = max(state[i-1]+array[i],array[i]);
        
        max_num = max(max_num,state[i]);
    }
    
    cout<<max_num<<endl;
    return 0;  
}

664. Strange Printer(奇怪的打印机)

题解

class Solution {
public:
    int strangePrinter(string s) {
        int size = s.size();
        if(size == 0){
            return 0;
        }
        vector<vector<int>> v(size, vector<int>(size, INT_MAX));
        
        for(int i=size-1;i>=0;i--){
            for(int j=i;j<=size-1;j++){
                // 分开打印
                v[i][j] = ((i==j)? 1: 1+v[i+1][j]);
                
                for(int k=i+1;k<j;k++){
                    if(s[i] == s[k]){
                        v[i][j] = min(v[i][j], v[i+1][k]+v[k+1][j]);
                    }
                }
                if(s[i] == s[j] && i!=j){
                    v[i][j] = min(v[i][j], v[i+1][j]);
                }
            }
        }
        return v[0][size-1];
    }
};

BM80 买卖股票的最好时机(一)

这种买入必须在卖出前面的,即当前位置的值只和前面有关的,非常适合于一次遍历

class Solution {
public:
    /**
     * 
     * @param prices int整型vector 
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        // write code here
        int min_price = INT_MAX;
        int profit = 0;
        int size = prices.size();
        
        for(int i=0;i<size;i++){
            profit = max(profit, prices[i] - min_price);
            min_price = min(min_price,prices[i]);
            
        }
        return profit;
    }
};

BM81 买卖股票的最好时机(二)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 计算最大收益
     * @param prices int整型vector 股票每一天的价格
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        // write code here
        int profit = 0;
         
        for(int i =1; i<prices.size();i++){
            int tmp = prices[i] -prices[i-1];
            if(tmp>0){
                profit+=tmp;
            }
        }
         
        return profit;
         
         
         
    }
};

BM82 买卖股票的最好时机(三)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 计算最大收益
     * @param prices int整型vector 股票每一天的价格
     * @return int整型
     */
    int maxProfit(vector<int>& prices) {
        // write code here
        int dp0 = 0;
        int dp1 = -prices[0];
        int dp2 = 0;
        int dp3 = -prices[0];
        int dp4 = 0;      
        for(int i=1;i<prices.size();i++){
            int dp0_0 = dp0;
            int dp1_1 = max(dp1, dp0 - prices[i]);
            int dp2_2 = max(dp2, dp1 + prices[i]);
            int dp3_3 = max(dp3, dp2 - prices[i]);
            int dp4_4 = max(dp4, dp3 + prices[i]);
            dp0 = dp0_0;
            dp1 = dp1_1;
            dp2 = dp2_2;
            dp3 = dp3_3;
            dp4 = dp4_4;
//             dp0 = dp0;
//             dp1 = max(dp1, dp0 - prices[i]);
//             dp2 = max(dp2, dp1 + prices[i]);
//             dp3 = max(dp3, dp2 - prices[i]);
//             dp4 = max(dp4, dp3 + prices[i]);
        }   
        return dp4;
    }
};

329. 矩阵中的最长递增路径

leetcode 329 矩阵中的最长递增路径

方法1: DFS + 动态规划

class Solution {
public:
    vector<vector<int>> directions{{0,-1},{0,1},{1,0},{-1,0}};
    int longestIncreasingPath(vector<vector<int>>& matrix) {
        int row_num = matrix.size();
        if(row_num == 0){
            return 0;
        }
        int col_num = matrix[0].size();
        if(col_num == 0){
            return 0;
        }

        vector<vector<int>> memo(row_num, vector<int>(col_num , 0));

        int max_length = 0;

        for(int i= 0; i<row_num;i++){
            for(int j=0;j<col_num;j++){
                max_length = max(max_length, dfs(matrix, i, j, memo));
            }
        }
        return max_length;
    }

    int dfs(vector<vector<int>>& matrix, int row, int col, vector<vector<int>>& memo){
        if(memo[row][col] !=0){
            return memo[row][col];
        }

        memo[row][col]++;

        for(int i=0;i<directions.size();i++){
                int new_row = directions[i][0] + row;
                int new_col = directions[i][1] + col;

                if(new_row >=0 && new_col>=0 && new_row<memo.size() && new_col < memo[0].size()){
                    if(matrix[new_row][new_col] > matrix[row][col]){
                        memo[row][col] = max(memo[row][col], 
                                             dfs(matrix, new_row, new_col, memo)+1);
                    }
                }

            
        }
        
        return memo[row][col];

    }

};

方法2:拓扑排序 + 动态规划
注意,这里是从出度为0的

class Solution {
public:

    vector<vector<int>> dirs = {{0,-1},{0,1}, {1,0},{-1,0}};
    int longestIncreasingPath(vector<vector<int>>& matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) {
            return 0;
        }

        int row_num = matrix.size();
        int col_num = matrix[0].size();
        vector<vector<int>> outdegrees(row_num, vector<int>(col_num, 0));
        queue<pair<int,int>> q;


        for(int i=0; i<row_num; i++){
            for(int j=0; j<col_num; j++){
                for(int dir=0;dir<dirs.size();dir++){
                    int newRow = i+dirs[dir][0];
                    int newCol = j+dirs[dir][1];

                    if(newRow>=0 && newCol>=0 && newRow<row_num && newCol < col_num && matrix[i][j] < matrix[newRow][newCol]){
                        outdegrees[i][j]++;
                    }
                }
               
            }
        }

        for(int i=0;i<row_num;i++){
            for(int j=0;j<col_num;j++){
                 if(outdegrees[i][j] == 0){
                    q.push(pair<int,int>(i,j));
                }
            }
        }

        int ans =0;

        //BFS
        while(!q.empty()){
            ans++;
            int tmp_size = q.size();
            for(int _=0;_<tmp_size;_++){
                pair<int, int> e = q.front();
                q.pop();

                int row = e.first;
                int col = e.second;

                for(int dir=0;dir<dirs.size();dir++){
                    int newRow = row + dirs[dir][0];
                    int newCol = col + dirs[dir][1];
\
                    if(newRow>=0 && newCol>=0 && newRow<row_num && newCol < col_num && matrix[row][col] > matrix[newRow][newCol]){
                        outdegrees[newRow][newCol]--;
                        if(outdegrees[newRow][newCol] == 0){
                            q.push(pair<int, int>(newRow, newCol));
                        }
                    }
                    
                }
            }
        }
        return ans;

    }
};

数组

leetcode 217存在重复元素

使用哈希表
unordered_set s;


链表

141. 环形链表

链表判环

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
   bool hasCycle(ListNode *head) {
       if(head == NULL){
           return false;
       }

       ListNode* slow;
       ListNode* fast;

       slow = fast = head;

       while(fast!= NULL && fast->next!= NULL){
           slow = slow->next;

           fast = fast->next->next;

           if(slow == fast){
               return true;
           }
       }
       
       return false;

   }
};



最大公约数

There are N chocolates in a circle. Count the number of chocolates you will eat.
题目

这道题的意思是,将N个巧克力排成一圈,我们每次都能走0, 1M, 2M, 3M, …, kM次。求能吃到的巧克力数量。

能吃到的巧克力数量 = (N和M的最小公倍数 / M)
而因为:
N和M的最小公倍数 = N*M / (N和M的最大公约数)

因此最后
能吃到的巧克力数量=N/(N和M的最大公约数)

面试题

京东算法,好串

小红定义一个字符串为好串,当且仅当相邻两个字母不相同。小红拿到了一个仅由’r’、‘e’、'd’三种字符组成的字符串,她有一个魔法:将相邻两个相同的字母同时删除,并在其位置生成任意一个字母(‘r’、‘e’、‘d’)三种中的一种。例如,对于字符串“dedd”,小红可以选择中间两个相邻字母“dd”,将其变成"r",此时字符串变为“der”。小红希望将给定的字符串变成“好串”。

输入一个长度不超过200000的、仅由’r’、‘e’、'd’三种字符组成的字符串。输出一个整数,代表操作的最小次数。

input:
rrrr

output:
1

s = input()
n = len(s)
i = 0
ans = 0
while i < n:
	cnt = 1
	while i< n-1 and s[i] == s[i+1]:
		cnt+=1
		i+=1
	i+=1
	ans+=(cnt+1) // 3
print(ans)
  1. 如果有2个r连续。 那么可以直接替换成和左右两边不冲突的
  • case 1
    d rr e -> d r e
  • case2
    d rr d -> d r d
  1. 如果有3个r连续。 那么替换1次:
  • case 1
    d rrr d -> d e r d
  • case 2
    d rrr e -> d e r e
  1. 如果有4个r连续。那么替换1次:
  • case 1
    d rrrr d -> d r d r d
  • case 2
    d rrrr e -> d r d r e
  1. 如果有5个r连续。那么:
  • case 1
    d rrrrr d -> d e r e d

从以上开出来是以3为周期的

艾方资产

把N*M的棋盘分割成若干个1*2的长方形,有多少种方案

瑞银

求一个数字序列里面和最大的子序列,它的和是多少?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值