leecode++理解_auto row : rows-程序员宅基地

技术标签: 算法  c++报错  数据结构  

climits头文件

INT_MAX

1 两数相加

给到一个目标值和 一个数组 返回数组中两数相加和等于目标值

方法1 暴力循环 两个for
方法2
建立哈希表 map
map中存放 键值对 键为 数 , 值为num【i】的位置i
然后一个个放入 num的数 ,一边放 一边查是否有,插入之前先找,防止找到的人是自己。

map.find为查找是否存在键

class Solution {
    
public:
    vector<int> twoSum(vector<int>& nums, int target) {
    
        unordered_map<int, int> hashtable;
        for (int i = 0; i < nums.size(); ++i) {
    
            auto it = hashtable.find(target - nums[i]);
            if (it != hashtable.end()) {
    
                return {
    it->second, i};
            }
            hashtable[nums[i]] = i;
        }
        return {
    };
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2 非空链表 两数相加

1 注意用指针接受由new创建的对象 直接就是地址

2 ListNode *head = nullptr, *tail = nullptr;

class Solution {
    
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    
        ListNode *head = nullptr, *tail = nullptr;
        int carry = 0;
        while (l1 || l2) {
    
            int n1 = l1 ? l1->val: 0;
            int n2 = l2 ? l2->val: 0;
            int sum = n1 + n2 + carry;
            if (!head) {
    
                head = tail = new ListNode(sum % 10);
            } else {
    
                tail->next = new ListNode(sum % 10);
                tail = tail->next;
            }
            carry = sum / 10;
            if (l1) {
    
                l1 = l1->next;
            }
            if (l2) {
    
                l2 = l2->next;
            }
        }
        if (carry > 0) {
    
            tail->next = new ListNode(carry);
        }
        return head;
    }
};

3

哈希集合 有点像set
滑动窗口思想
set从左边开始 不断往右边增加
左指针从0开始 然后右指针不断向右靠,同时判断右边的这个字符在set里有没有,没得话就加入,有的话就退出.
不断删set第一个字符,左指针不断加1

class Solution {
    
public:
    int lengthOfLongestSubstring(string s) {
    
        // 哈希集合,记录每个字符是否出现过
        unordered_set<char> occ;
        int n = s.size();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        // 枚举左指针的位置,初始值隐性地表示为 -1
        for (int i = 0; i < n; ++i) {
    
            if (i != 0) {
    
                // 左指针向右移动一格,移除一个字符
                occ.erase(s[i - 1]);
            }
            while (rk + 1 < n && !occ.count(s[rk + 1])) {
    
                // 不断地移动右指针
                occ.insert(s[rk + 1]);
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1);
        }
        return ans;
    }
};


       int lengthOfLongestSubstring(string s) {
    
        if(s.length()==1)
        return 1;
        int left=0, right = 0;

        int max1=0;
        int num = 0;
        unordered_set<char> set1;
        for(int i = 0; i<s.length(); i++)
        {
    

            while(!set1.insert(s[i]).second)
            {
    
                //max1 = max(max1,right-left+1);
                set1.erase(s[left]);
                left++;
            }
            max1 = max(max1,right-left+1);
            right++;
            //max1 = max(max1,right-left+1);
        }
        return max1;
    }

4 寻找两个有序数组的中位数

整数除法都是向下取整
所以不管偶数奇数
(m+n+1)/2 结果都是一样的

较短数组 在左边或者右边 没有元素
此时需要在较短数组确定位置 那么较长数组两边确定有位置。

当两个数组长度相同,那么有可能 两个都是 各占一边

为了防止访问数组下标越界, 将数量较少的 放在前面

在这里插入图片描述

在这里插入图片描述

total left = (m+n+1)/2 
等价于 m+ (n-m+1/2

在这里插入图片描述
left 大于等于right 成立 退出循环

二分查找思路为 不断分割确认 分割元素在左边还是右边

i的下标在中间位置 相当于 (a+b)/2

注意当左边界为i 并且 区间只有两个元素时, 会陷入死循环,因为他会不断判断
nums1[i-1] <= nums[j] 成立,然后 把i给left, 此时left小于right 进入循环
新的i成为 left +二分之一 仍旧是 left 搜索区间仍旧是 原来的两个元素的。

加上二分之一就会使left大于等于 right 从而跳出循环
同时由于加1 不会使 i取到0下标,从而0-1不会越界产生-1

同时这里考虑数组下标越界的情况

在这里插入图片描述
如果i 取到 0 就意味着 整个数组在右边 那么左边给一个象征意义上的最小值,保证不会被取到 因为取左边界两个数字中较大的

如果i为m 就是整个在左边,右边给一个象征意义最大值 取左边两个数字中最小的

j也是同理

5 最长字串

1 暴力解法
长度小于2 直接返回s
在这里插入图片描述
2 中心扩散法

	string longestPalindrome(string s) 
	{
    
		if (s.length() < 1)
		{
    
			return "";
		}
		int start = 0, end = 0;
		for (int i = 0; i < s.length(); i++)
		{
    
			int len1 = expandAroundCenter(s, i, i);//一个元素为中心
			int len2 = expandAroundCenter(s, i, i + 1);//两个元素为中心
			int len = max(len1, len2);
			if (len > end - start)
			{
    
				start = i - (len - 1) / 2;
				end = i + len / 2;
			}
		}
		return s.substr(start, end - start + 1);
	}

	int expandAroundCenter(string s, int left, int right)
	{
    
		int L = left, R = right;
		while (L >= 0 && R < s.length() && s[L] == s[R])
		{
    // 计算以left和right为中心的回文串长度
			L--;
			R++;
		}
		return R - L - 1;   注意 他这里 由于 R和L 都加了1 实际长度没那么长 所以减去了
	}

6

class Solution {
    
public:
    string convert(string s, int numRows) {
    
        if (numRows == 1) return s;
        vector<string> rows(numRows);
        // 行转向标志,极妙
        int flag = 1;  
        // 行下标索引
        int idxRows = 0;   
        for (int i = 0; i < s.size(); i++) {
    
            rows[idxRows].push_back(s[i]);
            // 更新行下标
            idxRows += flag;  
            if (idxRows == numRows - 1 || idxRows == 0) {
    
                // 转向,上——>下 | 下——>上
                flag = -flag;
            }
        }
        string res;
        for (auto row : rows) {
    
            // 拿到答案
            res += row;
        }
        return res;
    }
};


class Solution {
    
public:
	string convert(string s, int numRows) {
    

		if (numRows == 1) return s;

		vector<string> rows(min(numRows, int(s.size()))); // 防止s的长度小于行数
		int curRow = 0;
		bool goingDown = false;

		for (char c : s) {
    
			rows[curRow] += c;
			if (curRow == 0 || curRow == numRows - 1) {
    // 当前行curRow为0或numRows -1时,箭头发生反向转折
				goingDown = !goingDown;
			}
			curRow += goingDown ? 1 : -1;
		}

		string ret;
		for (string row : rows) {
    // 从上到下遍历行
			ret += row;
		}

		return ret;
	}
};

字母下标有规则
	string convert(string s, int numRows) {
    
		if (numRows == 1) return s;

		int step = numRows * 2 - 2; // 间距
		int index = 0;// 记录s的下标
		int len = s.length();
		int add = 0; // 真实的间距
		string ret;
		for (int i = 0; i < numRows; i++) // i表示行号
		{
    
			index = i;
			add = i * 2;
			while (index < len)//超出字符串长度计算下一层
			{
    
				ret += s[index]; // 当前行的第一个字母
				add = step - add;// 第一次间距是step -2*i,第二次是2*i, 
				index += (i == 0 || i == numRows-1) ? step : add; // 0行和最后一行使用step间距,其余使用add间距
			}
		}
		return ret;
	}

下标规律

7 整数反转

法1 数字转换字符串 to_string 字符串转换成数字 stoi
在C++中,std::stoi() 函数将字符串转换为整数。它的参数是 const std::string& 类型,可以表示一个包含数字的字符串。

对于 std::stoi() 函数,数字大小是有限制的,主要受到两个因素的影响:

整数类型的上限:在C++中,整数类型的上限由相应类型的数据表示范围决定。例如,如果使用 int 类型,则 std::numeric_limits::max() 代表该类型的最大值。如果尝试将超出这个范围的数字转换为 int 类型,std::stoi() 函数将引发 std::out_of_range 异常。

数字字符串本身的长度限制:如果尝试将太长的字符串转换为整数,std::stoi() 函数也会引发 std::out_of_range 异常。具体而言,在大多数实现中,字符串中的数字数量受到 size_t 类型的最大值(std::numeric_limitsstd::size_t::max()) 的限制。

综上所述,数字大小并非直接受到 std::stoi() 函数的限制,而是受到整数类型的数据表示范围和数字字符串长度的限制。

class Solution {
    
public:
    int reverse(int x) {
    
    string s = to_string(x);
    int n = s.size();
    string c;
    
    if(s[0]=='-')
    {
    
     c.push_back('-');
     for (int i = (n-1); i >0; i-- )
     {
    
        c.push_back(s[i]);
     }        
    }
    else{
    
        for (int i = (n-1); i >=0; i--)
        {
    
            c.push_back(s[i]);
        }        
    }
    
    int b = stoi(c);
    
    return b;}
};


class Solution {
    
    public int reverse(int x) {
    
        int res = 0;
        while(x!=0) {
    
            //每次取末尾数字
            int tmp = x%10;
            //判断是否 大于 最大32位整数
            if (res>214748364 || (res==214748364 && tmp>7)) {
    
                return 0;
            }
            //判断是否 小于 最小32位整数
            if (res<-214748364 || (res==-214748364 && tmp<-8)) {
    
                return 0;
            }
            res = res*10 + tmp;
            x /= 10;
        }
        return res;
    }
}			

  int reverse(int x) {
    
        string s=to_string(x);//变成字符串
        std::reverse(s.begin(), s.end());//翻转字符串 注意这里用了作用域 不然会有函数名的冲突
        int ans=0;
        try{
    
            ans=stoi(s);//变回数字
            if (x<0) ans=-ans;//x是负数,加上负号
        }catch(exception ex){
    }//溢出,啥也不做,返回零
        return ans;
    }

另外,因为 std::exception 是标准库中的一个基类,不会抛出具体的异常类型,因此在 catch 块中应该使用 catch(const std::exception& e) 的方式捕获异常。而在本代码中,catch(exception e) 只捕获了一个未指定类型的异常,并没有处理异常。建议修改为 catch(const std::exception& e) {
    },即空的 catch 块,这样可以避免程序崩溃。
在 catch(const std::exception& e){
    } 中,通过引用方式传递异常对象的好处是可以避免对象的拷贝和构造,从而提高程序的运行效率和性能。

此外,为了保证异常对象不会被修改,通常会在参数类型前加上 const 关键字。这样做可以防止在捕获异常时误修改异常对象的状态。如果在程序中需要修改异常对象的状态,可以将其声明为非常量引用,例如:catch(std::exception& e)。

需要注意的是,在某些情况下,如果异常对象是由值传递方式传递的,则在 catch 块中使用对象名称时,会发生值复制和对象构造,因此建议在 catch 块中始终使用引用方式传递异常对象,以避免不必要的开销。

综上所述,通过在 catch 块中传递 const 引用,可以避免对象的拷贝和构造,提高程序的运行效率和性能,并保证异常对象的状态不被修改。

8 8. 字符串转换整数 (atoi)

1-7

7. 整数反转

1 用了 try catch
2 使用字符串 数字抓换  to_string  stoi  
stoi会直接把s转换成数字 我看他代码里最后一位是符号的话不用管

3 不断地最后一位推出 除以10的余数

8. 字符串转换整数 (atoi)

1 自动机 相当于状态机

开始状态 标识符状态 数字状态 结束状态

int get_col(char c) {
    
    if (isspace(c)) return 0;
    if (c == '+' or c == '-') return 1;
    if (isdigit(c)) return 2;
    return 3;

 ans = ans * 10 + c - '0' 减去字符0的ascii值
 不然相加都是加的字符的 ascii的值

ans = sign == 1 ? min(ans, (long long)INT_MAX) : min(ans, -(long long)INT_MIN); 
我估计都必须是同型号的才能比较

2 字符流

#include<sstream>   
class Solution {
    
public:
    int myAtoi(string s) {
    
        stringstream liu(s);
        int n=0;
        liu>>n;
        return n;     
    }
};
c++,活用cin
 读取(和忽略)处于所需数据周围的标号,例如字符串是(“12 1”)int n,c; liu>>n>>c n的值是12,c的值是1

9 整型

1 我想的是从中间扩散 他的是从两边到中间
2 第二个想法是将数字本身反转,然后将反转后的数字与原始数字进行比较,如果它们是相同的,那么这个数字就是回文。
但是,如果反转后的数字大于
int.MAX
int.MAX,我们将遇到整数溢出问题。
那为什么不反转数字的一半

class Solution {
    
public:
    bool isPalindrome(int x) {
    
        if(x<0)
        return false;
        string s = to_string(x);
        int i=0 , j= s.length()-1;
        while(i<=j)
        {
    
           if(s[i]!=s[j])
              return false;
            i++;
            j--;      
        }
        return true;
    }
};



class Solution {
    
public:
    bool isPalindrome(int x) {
    
      string s=to_string(x);
      int n=s.size();
      if(s.length()<=1)
        return true;
      if(!isdigit(s[0]))
       return false;
      if(n%2==0)
      {
    
        int k=1; 
        for(int i = n/2; i<n; i++)
        {
    
            if(s[i]!=s[i-k])
            return false;
            k+=2;
        }
        
      }
      else
      {
    
        int k=2; 
        for(int i = (n/2 +1); i<n; i++)
        {
    
            if(s[i]!=s[i-k])
            return false;
            k+=2;
        }  
      }
      return true;  
    }
};



    bool isPalindrome(int x) {
    
        if (x<0)return false;
        if (x==0)return true;
       
        string s=to_string(x);
        int n=s.size();
        for(int i=0;i<n/2;i++){
    
            int j=n-1-i;
            if(s[i]!=s[j]){
    
                return false;
            }
        }
        return true;
    }
};

10. 正则表达式匹配

https://leetcode.cn/problems/regular-expression-matching/solution/by-flix-musv/
动态规划

dp[i][j] 表示s的前i个字符和p的前j个字符是否匹配·
原本是要看s的前i个字符和p的前j个字符是否匹配·
p[j]*     他这里是往前看的 后面的会考虑到前面的

如果匹配两次 意味着 s的i-1和i的字符要相同 ,并且 p的j-1字符也要相同
那么 i,j的问题 就转化为了 i-2和j-2的问题 以此往前
同样,如匹配k次 那么i,j的问题便转化为i-k和j-2的匹配问题
匹配0次,那么i,j的问题就可以转化为i,j-2的问题

他用了两个方程进行转化
得到了简化的状态方程
最后他得出了三种情况的方程
1 i,j字符匹配
那么就是要找i-1和 j-1匹配
否则直接false
2,p[j]* 那么接下来
 看 s[i]和 p[j-1]是否相等
  接下来又分两种情况
  

他这里提到了边界情况 两个都是空字符串那么 0,0位置
对于0,j 当j不是*时候,false 是的话 会引发j-2的情况 ,那么需要前面预留位置

class Solution {
    
public:
    bool isMatch(string s, string p) {
    
        if (p.empty()) return s.empty();
        
        auto first_match = !s.empty() && (s[0] == p[0] || p[0] == '.');
        
        if (p.length() >= 2 && p[1] == '*') {
    
            return isMatch(s, p.substr(2)) || (first_match && isMatch(s.substr(1), p));
        } else {
    
            return first_match && isMatch(s.substr(1), p.substr(1));
        }
    }
};

class Solution {
    
public:
    bool isMatch(string s, string p) {
    
        if(regex_match(s,regex(p)))
        {
    
            return true;
        }
        return false;
    }
};

class Solution {
    
public:
    bool isMatch(string s, string p) {
    
        return isMatch(s.c_str(), p.c_str());
    }
    
    bool isMatch(const char* s, const char* p) {
    
        if(*p == 0) return *s == 0;
        
        auto first_match = *s && (*s == *p || *p == '.');
        
        if(*(p+1) == '*'){
    
            return isMatch(s, p+2) || (first_match && isMatch(++s, p));
        }
        else{
    
            return first_match && isMatch(++s, ++p);
        }
    }
};

class Solution {
    
public:
    bool isMatch(string s, string p) {
    
        int m = s.size();
        int n= p.size();
        vector<vector<bool>> dp(m+1, vector<bool>(n+1, false));
        dp[0][0] = true;
        for(int j=1; j<=n; j++)
        {
    
            if(p[j-1]=='*') dp[0][j] = dp[0][j-2];//按题意p第一个元素不可能为'*'所以不必担心j越界
        }
        for(int i=1; i<=m; i++)
        {
    
            for(int j=1; j<=n; j++)
            {
    
                if(s[i-1]==p[j-1] || p[j-1]=='.') dp[i][j] = dp[i-1][j-1];
                else if(p[j-1]=='*')
                {
    
                    if(s[i-1]!=p[j-2] && p[j-2]!='.')
                    {
    
                        dp[i][j] = dp[i][j-2];
                    }
                    else
                    {
    
                        dp[i][j] = dp[i][j-2] | dp[i-1][j];
                    }
                }
            }
        }
        return dp[m][n];
    }
};

11 盛最多水的容器

int maxArea(vector<int>& height) {
    
    int max1=0;
    int area=0;
    int n = height.size();
    for(int i=0;i<n-1;i++)
    {
    
        for(int j=i+1 ; j<n;j++)
        {
    
            area= min(height[i],height[j])*(j-i);
            max1= max(area,max1);
        }
    }
    return max1;
}


class Solution {
    
public:
    int maxArea(vector<int>& height) {
    
        int i = 0, j = height.size() - 1, res = 0;
        while(i < j) {
    
            res = height[i] < height[j] ? 
                max(res, (j - i) * height[i++]): 
                max(res, (j - i) * height[j--]); 
        }
        return res;
    }
};

class Solution {
    
public:
    int maxArea(vector<int>& height) {
    
    
    
    int i=0,j=height.size()-1,area1=0;
    int max1=0;
    while(i!=j)
    {
    
      
      area1= (j-i)*min(height[i],height[j]);
      max1= max1>area1?max1:area1;
      if(height[i]>height[j])
      {
    
          j--;
      }
      else
      {
    
          i++;
      }


    }
    return max1;
    }
};

长短板
两边 长的往里进 短的不变,长的变得更短,不可能变大
短的往里进 还有可能变大

13 13. 罗马数字转整数

小的在右边 加
小的在左边 减去

class Solution {
    
public:
    int romanToInt(string s) {
    
    // string x1[] = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        //String[] rom={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
      //  int x2[] = {1000,900,500,400,100,90,50,40,10,9,5,4,1};

      unordered_map<string,int> hashmap= {
     {
    "M",1000},{
    "CM",900},{
    "D",500},{
    "CD",400},{
    "C",100},{
    "XC",90},{
    "L",50},{
    "XL",40},{
    "X",10},{
    "IX",9},{
    "V",5},{
    "IV",4},{
    "I",1}};
      int ans = 0;
      //string ss="";
      for(int i=0;i<s.length();i++)
      {
    
         if(i+1<s.length() )
         {
      
            string s1(1,s[i]);
            string s2(1,s[i+1]); 
            if(hashmap[s1]>=hashmap[s2])
             ans+=hashmap[s1];
            else 
                {
    
                    ans+=hashmap[s1+s2];
                    i++;
                }

         }
         else if(i==s.length()-1)
         {
    
             string s1(1,s[i]);
             ans+=hashmap[s1];
         }

         

      }
      return ans;

    }
};


class Solution {
    
private:
    unordered_map<char, int> symbolValues = {
    
        {
    'I', 1},
        {
    'V', 5},
        {
    'X', 10},
        {
    'L', 50},
        {
    'C', 100},
        {
    'D', 500},
        {
    'M', 1000},
    };

public:
    int romanToInt(string s) {
    
        int ans = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
    
            int value = symbolValues[s[i]];
            if (i < n - 1 && value < symbolValues[s[i + 1]]) {
    
                ans -= value;
            } else {
    
                ans += value;
            }
        }
        return ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/roman-to-integer/solution/luo-ma-shu-zi-zhuan-zheng-shu-by-leetcod-w55p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1673 最具竞争子序列

使用单调栈

    vector<int> mostCompetitive(vector<int>& nums, int k) {
    
        
       int n = nums.size();
    int count= n-k;
    vector<int> ans;
    for(int i = 0; i<n;i++)
    {
    
    while(!ans.empty() && ans.back()>nums[i] && count>0)
    {
    
        ans.pop_back();
        count--;
    }
    ans.push_back(nums[i]);
    }

    while(ans.size()>k)
    {
    
    ans.pop_back();
    }
    return ans;
        }

207 课程表

他这个课程表 课程数量和 有的课是相同的

for cur, pre in prerequisites:
indegrees[cur] += 1 [ xx] 在课程位置数加1 代表该课程的入度数加1
adjacency[pre].append(cur) 在 pre课程位置的 【】内加入 出度的课程号 即依赖这门课的后续课程
遍历 indegress 如果他的入度数为0 就把该位置相当于课号的加入 队列
此时 queue 应该是 按照课程号顺序排列的,并且都是入度数为0的,相当于第一层节点

当queue不为空,就不断推出队首的一个值,
然后根据这个值看依赖他的课程号,然后把该课程号的入度数减去1,并判断 这个课程入度数是否为0,是的话就推入queue

queue都遍历完了 然后 把 numcourses返回

DFS法

class Solution {
    
private:
    vector<vector<int>> edges;
    vector<int> visited;
    bool valid = true;

public:
    void dfs(int u) {
    
        visited[u] = 1;
        for (int v: edges[u]) {
    
            if (visited[v] == 0) {
    
                dfs(v);
                if (!valid) {
    
                    return;
                }
            }
            else if (visited[v] == 1) {
    
                valid = false;
                return;
            }
        }
        visited[u] = 2;
    }

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    
        edges.resize(numCourses);
        visited.resize(numCourses);
        for (const auto& info: prerequisites) {
    
            edges[info[1]].push_back(info[0]);
        }
        for (int i = 0; i < numCourses && valid; ++i) {
    
            if (!visited[i]) {
    
                dfs(i);
            }
        }
        return valid;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


广度优先
class Solution {
    
private:
    vector<vector<int>> edges;
    vector<int> indeg;

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    
        edges.resize(numCourses);
        indeg.resize(numCourses);
        for (const auto& info: prerequisites) {
    
            edges[info[1]].push_back(info[0]);
            ++indeg[info[0]];
        }

        queue<int> q;
        for (int i = 0; i < numCourses; ++i) {
    
            if (indeg[i] == 0) {
    
                q.push(i);
            }
        }

        int visited = 0;
        while (!q.empty()) {
    
            ++visited;
            int u = q.front();
            q.pop();
            for (int v: edges[u]) {
    
                --indeg[v];
                if (indeg[v] == 0) {
    
                    q.push(v);
                }
            }
        }

        return visited == numCourses;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。




class Solution {
    
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    
        vector<int> degrees(numCourses);//记录所有顶点的入度,未初始化的为0
        vector<vector<int>> adjacents(numCourses); //邻接表
        queue<int> zero;//零入度的顶点
        int num = numCourses;
        for(int i=0;i<prerequisites.size();i++)
        {
    
            degrees[prerequisites[i][0]]++;//入顶点
            adjacents[prerequisites[i][1]].push_back(prerequisites[i][0]);//出顶点
        }
        for(int i=0;i<numCourses;i++)
            if(degrees[i]==0){
    
                zero.push(i); //入度为0的先入队列
                num--;
            }
                
        while(!zero.empty()){
    
            int temp = zero.front();
            zero.pop();
            for(int j=0;j<adjacents[temp].size();j++)
                if(--degrees[adjacents[temp][j]]==0){
    
                    zero.push(adjacents[temp][j]);
                    num--;
                }
                    
        }
        if(num==0)
            return true;
        return false;
    }

BFS

广度优先即按层去遍历整个图,一层访问结束后再去访问下一层。

DFS

https://blog.csdn.net/yanweiqi1754989931/article/details/109603384
https://blog.csdn.net/m0_46213598/article/details/120363633

建立依赖表 就是依赖这个课程的 课程
为每个课程建立0标签

对于每一个课程, if not dfs,返回假
不然返回真

dfs 是0的话就返回假了 基本上dfs得是1
dfs 三个参数 分别是 课程号 课程的依赖课 该课程的标签
对于i课程dfs中 对他的依赖课程dfs
要想这个不执行 得是他的依赖课程dfs都是 true
都执行完 ,该课程标签置为-1
就是判断是否有环,有环就不行了

1704 判断字符串的两半是否相似

我的想法是把字符串分成两半 再两边找
他直接是构建了一o, 然后拿s里的字母一个个到o里找

class Solution {
    
public:
    bool halvesAreAlike(string s) {
    
        string o = "aeiouAEIOU";
        int n = s.length();
        int cout1=0,cout2=0;
        for(int i=0; i< n; i++ )
        {
    
            int pose1=o.find(s[i]);
            if(pose1!= -1)
            {
    
                i<n/2? cout1++:cout2++;
            }    

        }
        if(cout1 ==cout2) return true;
        else return false;
    }
};

1705 吃苹果最大数目

https://blog.csdn.net/hnjzsyjyj/article/details/108929993

priority queue元素 队列中元素按照优先级参数排序,最小或者最大的元素总是在队列前端,并且会在每次出队的时候被删除
greater 从大到小

priority_queue<int,vector,less>q2;//神奇的降序
大家可以看到,默认模板有三个参数,第一个是优先队列处理的类。第二个参数比较有特点,是容纳优先队列的容器。实际上,优先队列是由这个容器C++语言中关于heap的相关操作实现的。这个容器默认是vector,也可以是dequeue,因为后者功能更强大,而性能相对于vector较差,考虑到包装在优先队列后,后者功能并不能很好发挥,所以一般选择vector来做这个容器。第三个参数比较重要,支持一个比较结构,默认是less,默认情况下,会选择第一个参数决定的类的<运算符来做这个比较函数。

priority_queue<int, vector, greater >
qi2;//从小到大的优先级队列,可将greater改为less,即为从大到小

可以使用优先队列存储每个苹果的腐烂日期 最小元素会被先取出

看一下当天pq中已经过期的 直接删掉 然后加入当天新鲜的

当pq非空,并且他的top的first元素小于等于i pq插入 腐烂的天数以及腐烂的数目 推出top 然后把腐烂数目减1 然后如果还有数目
就加入

只要pq不为空 一直执行循环 , 然后首先当天去掉过期的 再次判断 是不是空了 ,空的话就推出循环,不然就拿出top并推出 int num
= min(curr.first - i, curr.second); 分析两个数字中小的, 第一个是还有几天过期,比如两天过期, 第二个是还剩下几个苹果,比如三个苹果, 那么可以吃的数量就是两个 然后一个天数一个苹果树分别加上最小值

class Solution {
    
public:
    int eatenApples(vector<int>& apples, vector<int>& days) {
    
        int ans = 0;
        int d = 0;

        map<int, int> m; // (expire, cnt)

        while (d < days.size() || !m.empty()) {
    
            if (d < days.size()) m[days[d]+d-1] += apples[d];
            
            // 尝试从map中取出一个最接近过期但是没有过期的苹果
            while(!m.empty()) {
    
                if (m.begin()->first < d || m.begin()->second == 0) m.erase(m.begin()->first);
                else {
    
                    // 如果找到了 我们就吃掉它
                    ans++;
                    // 苹果数要减1
                    m.begin()->second--;
                    break;
                }
            }
            d++;
        }

        return ans;
    }
};

作者:wfnuser
链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/solution/wei-rao-li-lun-tan-xin-dui-mei-ci-zhao-z-txr2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



class Solution {
    
public:
    int eatenApples(vector<int>& apples, vector<int>& days) {
    
        int ans = 0;
        int d = 0;

        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;

        while (d < days.size() || !q.empty()) {
    
            if (d < days.size()) q.push(make_pair(days[d]+d-1, apples[d]));
            auto apple = q.top();
            // 跳过所有已经过期的苹果
            while (apple.first < d) {
    
                q.pop();
                if (q.size() == 0) break;
                apple = q.top();
            }
            // 如果没有没过期的苹果,继续下一天的等待
            if (q.size() == 0) {
     d++; continue; }
            // 如果有可以吃的苹果;我们要把这一天过期的苹果数量减1
            if (apple.second > 0) {
    
                q.pop();
                apple.second--;
                // 如果苹果还有剩余,我们把它放回堆中
                if (apple.second > 0) q.push(apple);
                ans++;
            }
            d++;
        }

        return ans;
    }
};

作者:wfnuser
链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/solution/wei-rao-li-lun-tan-xin-dui-mei-ci-zhao-z-txr2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



typedef pair<int,int> pii;

class Solution {
    
public:
    int eatenApples(vector<int>& apples, vector<int>& days) {
    
        int ans = 0;
        priority_queue<pii, vector<pii>, greater<pii>> pq;
        int n = apples.size();
        int i = 0;
        while (i < n) {
    
            while (!pq.empty() && pq.top().first <= i) {
    
                pq.pop();
            }
            int rottenDay = i + days[i];
            int count = apples[i];
            if (count > 0) {
    
                pq.emplace(rottenDay, count);
            }
            if (!pq.empty()) {
    
                pii curr = pq.top();
                pq.pop();
                curr.second--;
                if (curr.second != 0) {
                      
                    pq.emplace(curr.first, curr.second);
                }
                ans++;
            }
            i++;
        }
        while (!pq.empty()) {
    
            while (!pq.empty() && pq.top().first <= i) {
    
                pq.pop();
            }
            if (pq.empty()) {
    
                break;
            }
            pii curr = pq.top();
            pq.pop();
            int num = min(curr.first - i, curr.second);
            ans += num;
            i += num;
        }
        return ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/solution/chi-ping-guo-de-zui-da-shu-mu-by-leetcod-93ka/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1706 球会落在何处

class Solution {
    
public:
    vector<int> findBall(vector<vector<int>>& grid) {
    
        int col = grid[0].size();
        vector<int> res;
        for(int i=0; i<col;i++)
        {
    
          int j =0;  
          while(j<grid.size())  
          {
    
            int cur = grid[j][i];
            i+= grid[j][i]; //action
            if(i>=0 ||i<col)
            {
    
              int nei = grid[j][i];
              if(nei*cur>0) j++;
              else 
                break;  
            }
            
          }  
          j==grid.size()-1? res.push_back(i+1):res.push_back(-1);  

        }
        return res;
    }
}; 


    vector<int> findBall(vector<vector<int>> &grid) {
    
        int n = grid[0].size();
        vector<int> ans(n);
        for (int j = 0; j < n; ++j) {
    
            int col = j; // 球的初始列
            for (auto &row : grid) {
    
                int dir = row[col];
                col += dir; // 移动球
                if (col < 0 || col == n || row[col] != dir) {
     // 到达侧边或 V 形
                    col = -1;
                    break;
                }
            }
            ans[j] = col; // col >= 0 为成功到达底部
        }
        return ans;
    }

1706 球会落在何处

考虑col中的数字为方向,然后根据方向更新col,此时看col是否为边界,并看此时col中的数字是否一致,不然的话条件不满足,球被卡死,无法进入到下一层。

1530好叶子的数量

递归
首先判断是不是空指针 是的话返回{}
然后判断他的左右节点是不是空 是的话返回0

设立了一个 vector ret
遍历左系欸但 返回的left是

/ 他是按层来的,从下往上。 最下面的叶子计算层数,比方说左和右,计算距离。
计算完成后返回上一层dfs,此时的下层的左和右都会统一变成上一层的左 或者是 右。

class Solution {
    
public:
    int countPairs(TreeNode* root, int distance) {
    
        int ans = 0;
        dfs(root, distance, ans);
        return ans;
    }

    vector<int> dfs(TreeNode* root, int distance, int& ans) {
    
        if (root == nullptr) return {
    };
        if (root->left == nullptr && root->right == nullptr) return {
     0 };

        vector<int> ret;
        auto left = dfs(root->left, distance, ans);
        for (auto& e : left) {
    
            if (++e > distance) continue;
            ret.push_back(e);
        }
        auto right = dfs(root->right, distance, ans);
        for (auto& e : right) {
    
            if (++e > distance) continue;
            ret.push_back(e);
        }

        for (auto l : left) {
    
            for (auto r : right) {
    
                ans += (l + r <= distance);
            }
        }

        return ret;
    }
};

1391 有效路劲

静态连通
给定整个图 再给出连通性的询问
https://leetcode.cn/problems/check-if-there-is-a-valid-path-in-a-grid/solution/jian-cha-wang-ge-zhong-shi-fou-cun-zai-you-xiao-lu/

并查集
class Solution {
int m,n,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};//0下、1右、2上、3左
int pipe[7][4]={ {-1,-1,-1,-1},{-1,1,-1,3},{0,-1,2,-1},{-1,0,3,-1},{-1,-1,1,0},{3,2,-1,-1},{1,-1,-1,2}};
//记录各个拼图块路径的方向,0、1、2、3代表方向,-1代表不可走。
bool dfs(int x,int y,int dir,vector<vector>& grid){//(x,y,当前方向,地图)
if(xm-1&&yn-1) return 1;//到达终点
int xx=x+dx[dir];
int yy=y+dy[dir];//得到下一个准备走的坐标
if(xx<0||yy<0||xx>=m||yy>=n)return 0;//越界
int nxt=grid[xx][yy];//得到下一块拼图的编号
if(pipe[nxt][dir]!=-1)return dfs(xx,yy,pipe[nxt][dir],grid);//如果当前方向可走,则方向改变,继续走。
return 0;//无法走,返回0
}
public:
bool hasValidPath(vector<vector>& grid) {
m=grid.size();
n=grid[0].size();
int sta=grid[0][0];//起点的拼图编号
for(int i=0;i<4;++i)//朝着四个方向都试一下
if(pipe[sta][i]!=-1)//当前方向可以走
if(dfs(0,0,pipe[sta][i],grid))//沿着当前方向搜索
return 1;//拼图都有两个方向可以走,只要沿着一个初始方向走通就可以。
return 0;
}
};

作者:wu-xing-que-ni-2
链接:https://leetcode.cn/problems/check-if-there-is-a-valid-path-in-a-grid/solution/cdfsjie-fa-rong-yi-li-jie-dai-ma-duan-zhu-shi-duo-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2443 反转后的数字和

暴力枚举

 string temp=to_string(num);
        reverse(temp.begin(),temp.end());
        return stoi(temp);

15 三数之和

class Solution {
    
public:
    vector<vector<int>> threeSum(vector<int>& nums)
{
    
    vector< vector<int> > ans;
    if(nums.size() < 3 || nums.empty()) return ans; // 特判
    int n = nums.size();

    sort(nums.begin(), nums.end()); //排序
    for(int i = 0; i < n; i++)  // 枚举最小值
    {
    
        if(nums[i] > 0) return ans;
        if(i > 0 && nums[i] == nums[i-1]) continue;   // 最小元素去重!
        int l = i+1;
        int r = n-1;
        while(l < r)    // 枚举中间值和最大值
        {
    
            int x = nums[l] + nums[r] + nums[i];
            if(x == 0){
     // 符合条件,存储,并且去重,双端都移到下一个位置
                ans.push_back({
     nums[i], nums[l], nums[r] });
                while( l < r && nums[l] == nums[l+1]) l++; l++;
                while( l < r && nums[r] == nums[r-1]) r--; r--;
            }
            else if(x > 0) // 大了就让右边最大值变小
                r--;
            else        // 小了就让左边中间值变大
                l++;
        }
    }
    return ans;
}
};

2438. 二的幂数组中查询范围内的乘积

https://blog.csdn.net/weixin_44020969/article/details/103225825

https://leetcode.cn/problems/range-product-queries-of-powers/

class Solution {
    
public:
    vector<int> two(int &n)
    {
    
       vector<int> ans;
       int i=0;
       while(n>0)
       {
    
        if(n&1)
        {
    
          ans.push_back(1 << i);
        }
        n >>= 1;
        i++;
    }
    //reverse(ans.begin(),ans.end());
    return ans;
}
    vector<int> productQueries(int n, vector<vector<int>>& queries) {
    
        vector<int> power= two(n),ans;
        
        for(int i=0;i<queries.size();i++)
        {
    
          int j = queries[i][0];
          long tem = 1;
          while(j<=queries[i][1])
           {
    
             tem = tem*power[j]%1000000007;
             j++;
           }             
          ans.push_back(tem);
          tem = 1;
        }
        return ans;
    }
};




class Solution {
    
public:
    vector<int> productQueries(int n, vector<vector<int>>& queries) {
    
        const int MOD = 1e9 + 7;
        vector<int> powers, prefix;
        long long tmp = n, base = 1;
        while (tmp > 0) {
    
            if (tmp & 1) powers.push_back(base);
            base = (base * 2LL) % MOD;
            tmp >>= 1;
        }
        prefix.push_back(1);
        for (int i = 0; i < powers.size(); ++i) {
    
            prefix.push_back((long long)prefix.back() * powers[i] % MOD);
        }
        vector<int> answers;
        for (auto& query : queries) {
    
            int left = query[0], right = query[1] + 1;
            long long res = (long long)prefix[right] * inverse(prefix[left], MOD) % MOD;
            answers.push_back(res);
        }
        return answers;
    }
private:
    int inverse(int a, int m) {
    
        int m0 = m, t, q;
        int x0 = 0, x1 = 1;
        if (m == 1) return 0;
        while (a > 1) {
    
            q = a / m;
            t = m;
            m = a % m;
            a = t;
            t = x0;
            x0 = x1 - q * x0;
            x1 = t;
        }
        if (x1 < 0) x1 += m0;
        return x1;
    }
};


2125. 银行中的激光束数量

int numberOfBeams(vector<string>& bank) {
    
  int row = bank.size();
  int las1=0;

  vector<int> num;
  int ans;  
  for(int i=0; i<row; i++)
  {
    
      for(char c:bank[i])
      {
    
          if(c=='1')
          las1++;        
      }
      if(las1!=0)
      num.push_back(las1);
      las1=0;
  }
  for(int i=0; i<num.size()-1; i++)
  {
    
    int tem= num[i]*num[i+1];
    ans+=tem;

  }  

    return ans;

}


class Solution {
    
public:
    int numberOfBeams(vector<string>& bank) {
    
        int res = 0;
        int pre = 0;
        for (auto &s : bank) {
    
            int cur = 0;
            for (char &c : s) {
    
                cur += c == '1';
            }
            if (cur > 0) {
    
                res += pre * cur;
                pre = cur;
            }
        } 
        return res;
    }
};


class Solution {
    
public:
    int numberOfBeams(vector<string>& bank) {
    
        int last = 0, ans = 0;
        for (const string& line: bank) {
    
            int cnt = count_if(line.begin(), line.end(), [](char ch) {
    return ch == '1';});
            if (cnt != 0) {
    
                ans += last * cnt;
                last = cnt;
            }
        }
        return ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/number-of-laser-beams-in-a-bank/solution/yin-xing-zhong-de-ji-guang-shu-shu-liang-ad02/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

941 有效的山脉数组

class Solution {
    
public:
    bool validMountainArray(vector<int>& arr) {
    
        int n = arr.size();
        if(n<3) return false;
        int flag=0;
        for(int i=0;i<n-1;i++)
        {
    
            if(flag==0)
            {
    
               if(arr[i]>=arr[i+1]) return false;
               if(arr[i]<arr[i+1]) flag=1; 
            }
            else if(flag==1)
            {
    
               if(arr[i]==arr[i+1]) return false;
               if(arr[i]>arr[i+1]) flag=2;     
            }
            else
            {
    
               if(arr[i]<=arr[i+1]) return false;
            }
        }
        
        if(flag==2)
        return true;
        else
        return false;
    }
};


class Solution {
    
public:
    bool validMountainArray(vector<int>& arr) {
    
        int n = arr.size();
        if(n<3) return false;
        int flag=0;
        for(int i=0;i<n-1;i++)
        {
    
            if(flag==0)
            {
    
               if(arr[i]>=arr[i+1]) return false;
               if(arr[i]<arr[i+1]) flag=1; 
            }
            else if(flag==1)
            {
    
               if(arr[i]==arr[i+1]) return false;
               if(arr[i]>arr[i+1]) flag=2;     
            }
            else
            {
    
               if(arr[i]<=arr[i+1]) return false;
            }
        }
        
        if(flag==2)
        return true;
        else
        return false;
    }
};
const validMountainArray = (A) => {
    
  const n = A.length;
  let i = 0;
  let j = n - 1;

  while (i + 1 < n && A[i] < A[i + 1]) {
    
    i++;
  }
  while (j - 1 >= 0 && A[j - 1] > A[j]) {
    
    j--;
  }
  if (i != 0 && i == j && j != n - 1) {
    
    return true;
  }
  return false;
};


可以使用两种指针,一个从左边找最高山峰,一个从右边找最高山峰,最后判断找到的是不是同一个山峰

1657. 确定两个字符串是否接近

思路 直接统计两个字符串中 不同字符的个数 是否相同

class Solution {
    
public:
    bool closeStrings(string word1, string word2) 
    {
    
        int m = word1.size();
        int n = word2.size();
        if (m != n)
            return false;
        vector<int> repeat1(26, 0), repeat2(26, 0);
        for (int i = 0; i < m; ++i)
        {
    
            ++repeat1[word1[i] - 'a'];
            ++repeat2[word2[i] - 'a'];
        }
        for (int i = 0; i < 26; ++i)
            if ((repeat1[i] == 0) ^ (repeat2[i] == 0))   异或运算符 其实就是判断两个 如果一个是0 一个不是 那么不成立
                return false;							  我想着把这段删了 只要下面的for就行,但是不太行
        sort(repeat1.begin(), repeat1.end());				因为这里只是  数量对上了  转换后字母不同
        																例如 "uau"  "ssx"  
        sort(repeat2.begin(), repeat2.end());
        for (int i = 0; i < 26; ++i)
            if (repeat1[i] != repeat2[i])
                return false;
        return true;
    }
};

作者:Dahri
链接:https://leetcode.cn/problems/determine-if-two-strings-are-close/solution/tong-ji-zi-fu-de-chu-xian-ci-shu-jiu-hao-liao-by-p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

962 最大宽度坡

我的思路 滑动窗口法,最大宽度从 n 开始不断往下减少

一开始最大n只有一个 上标0 下标n-1
后面有两个 上标0或者1 下标 n-2 或者 n-1

class Solution {
    
public:
    int maxWidthRamp(vector<int>& nums) {
    
    
    int n=nums.size()-1;
    int k=nums.size()-1;

    while(n>0)
    {
    
        for(int i=0; i<=k-n;i++)
        {
    
            if(nums[i]<=nums[n+i])
            return n;
        }
        n--;

    }
    return 0;
    }
};
超出时间限制

单调栈

单调递增栈就是从栈底到栈顶是从小到大;
单调递减栈就是从栈底到栈顶是从大到小。

他这里构建的代码就是 栈底元素最大 顶部元素最小,从nums中标号0开始的
然后 nums 栈顶标号元素 小于 nums j 就给到栈顶pos,然后推出

class Solution
{
    
public:
    int maxWidthRamp(vector<int> &nums)
    {
    
        stack<int> s;
        int res = 0;
        int n = nums.size();
        s.push(0);
        for (int i = 0; i < n; ++i)
        {
    
            if (s.empty() || nums[s.top()] > nums[i])
                s.push(i); // 严格单调递减栈
        }
        for (int j = n - 1; j >= res; --j) // 当然你要写成j >= 0也是可以AC的
        {
    
            while (s.size() && nums[s.top()] <= nums[j])
            {
    
                int pos = s.top();
                s.pop();
                res = max(res, j - pos);
            }
        }
        return res;
    }
};

作者:Algo-Goer
链接:https://leetcode.cn/problems/maximum-width-ramp/solution/c-962-zui-da-kuan-du-po-ti-jie-dan-diao-5ztod/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

def maxWidthRamp(A):
    stack = []
    max_width = 0

    # 构建单调递减栈
    for i, num in enumerate(A):
        if not stack or A[stack[-1]] > num:
            stack.append(i)

    # 从右向左遍历数组,查找最大宽度坡
    for j in range(len(A) - 1, -1, -1):
        while stack and A[stack[-1]] <= A[j]:
            i = stack.pop()
            max_width = max(max_width, j - i)

    return max_width

作者:3k5X21s3ar
链接:https://leetcode.cn/problems/maximum-width-ramp/solution/bao-jiao-bao-hui-shi-jian-fu-za-du-onkon-3lji/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解题思路:使用递减栈求解该最大跨度问题“找到满足 A[j] >= A[i] 的最大跨度 [i,j]”。
理论依据:1.栈中保存的元素依次为比 A 首元素逐步降低的元素索引,对于任意区间 [i,j] ,无妨设 i 不是栈顶元素,若其满足 A[j] >= A[i] ,则对于栈中比 i 小的最大索引 i_0 < i (此时 i_0 是正序遍历至 i 处时的栈顶元素),区间 [i_0,j] 必满足 A[j] > A[i_0] ,这是因为栈顶元素是递减的,因为 i 元素不在栈中而 i_0 是正序遍历至 i 处时的栈顶元素,故必有 A[i_0] < A[i] ,即区间 [i_0,j] 是比区间 [i,j] 更优的解,故,对于最优解的区间 [i,j] , i 必是某个栈顶元素;

i_0是栈里的,单调递减,他的元素起码小于等于 i上的元素,所以条件更成立,并且i_0还是小于i
相当于从0开始依次检测是否入栈,严格小于栈顶的才入栈
之后比方说到了 数组的i位置处,i的元素不足以入栈,当前的栈顶元素i_0所代表的,值比i
的小,位置也比他考前,所以理应更比他适合

2.在将 j 从 A 尾元素向左移动的过程中,若 A[j] >= A[heightStack.top()] 则可以将 heightStack.top() 弹出,因为 heightStack.top() 成为跨度左界的情况的跨度最大值已计算完毕,否则可以将 j 向左移动一位,因为 j 成为跨度右界的情况的跨度最大值已计算完毕,这是因为若 A[j] 小于当前栈顶元素,则 A[j] 必小于栈中其他元素。
算法过程:首先基于 A 数组构造递减栈;随后使用递减栈求出满足 A[j] >= A[i] 的最大跨度 [i,j] ,具体地,从 A 尾元素开始移动 j ,若 A[j] >= A[heightStack.top()] 则将 heightStack.top() 弹出,否则将 j 向左移动一位。
算法细节:当递减栈弹出至空时,可提前结束查找。

这里再前面建立单调栈的基础上,将整个数组的元素 从右往左逐个检验,

栈底到栈顶是从小到大
栈顶先出,栈底后出
先出大的,后出小的,所以单调递减
构造递减栈, 遍历,只要比栈顶小,就推入,从而越来越小,压在里面的是最大的。
栈中元素从深到浅 依次为 比首元素 减小的 元素索引
那么索引可能是
0 1 2 3 索引不断增大,先出3,再出2,

2587. 重排数组以得到最大前缀分数

class Solution {
    
public:
    int maxScore(vector<int>& nums) {
    
       //int score = 0;
       double num =0;
       //vector<int> prefix;
       sort(nums.begin(),nums.end(),greater<int>());
       int i=0;
       while(num>=0)
       {
    
           num+=nums[i];
           i++;
           if(num<=0) 
           {
    
               i--;
               break;}
           if(i>=nums.size()) break; 
       } 
       return i;
    }
};

class Solution {
    
    public int maxScore(int[] nums) {
    
        // 从小到大排序
        Arrays.sort(nums);
        int maxScore = 0;
        // 前缀和
        long preFixSum = 0;
        // 倒序求正数前缀和
        for (int i = nums.length - 1; i >= 0; i--) {
    
            preFixSum += nums[i];
            if (preFixSum > 0) {
    
                maxScore++;
            } else {
    
                // 出现负数,终止遍历
                // nums的分数是prefix数组中正整数的个数
                return maxScore;
            }
        }
        return maxScore;
    }
}

作者:fa-xing-bu-luan
链接:https://leetcode.cn/problems/rearrange-array-to-maximize-prefix-score/solution/6316-zhong-pai-shu-zu-yi-de-dao-zui-da-q-ofi7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2342. 数位和相等数对的最大和

遍历将数位和求出并加入map
然后遍历map map后面的值的长度大于二,就将v排序,从大到小,取前两个相加。

   map<int, vector<int>> mp;


class Solution {
    
public:
    int maximumSum(vector<int>& nums) {
    
        map<int, vector<int>> mp;
        for(auto c : nums){
    
            int sum = 0, t = c;
            while(c){
    
                sum += c % 10;
                c /= 10;
            }
            mp[sum].push_back(t);
        }
        int ans = -1;
        for(auto [k, v] : mp){
    
            if(v.size() == 1) continue;
            
            sort(begin(v), end(v));
            int n = v.size();
            ans = max(v[n-1] + v[n-2], ans);
        }
        return ans;
    }
};

剑指 Offer 34. 二叉树中和为某一值的路径

一种思想就是 遍历每一条路径 ,然后把该路径的值计算

一种思想就是 每一层 然后每一层判断

/**
 * 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>> ret;
    vector<int> path;

    void dfs(TreeNode* root, int target) {
    
        if (root == nullptr) {
    
            return;
        }
        path.emplace_back(root->val);
        target -= root->val;
        if (root->left == nullptr && root->right == nullptr && target == 0) {
    
            ret.emplace_back(path);
        }
        dfs(root->left, target);
        dfs(root->right, target);
        path.pop_back();
    }

    vector<vector<int>> pathSum(TreeNode* root, int target) {
    
        dfs(root, target);
        return ret;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/solution/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-68dg/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

452. 用最少数量的箭引爆气球

https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/solution/tu-jie-tan-tao-wei-shi-yao-yao-an-qu-jian-de-you-d/

贪心。 右边断点从小到大排序,然后以右端点为参考点, 不断判断下一个的左端点是否小于,是的话判断下一个, 直到不是 那么这个时候弓箭加1
按左端右端排序都是一样的,都是寻求最小交集区间。[0,9]和[0,6]交集[0,6],所以[0,6]上可以一箭射穿,[0,6]和[7,8]没有交集,所以箭数+1。

class Solution {
    
public:
    static bool cmp(vector<int> &a,vector<int> &b)
    {
    
       return a[1] < b[1];
    }

    int findMinArrowShots(vector<vector<int>>& points)
    {
    
        //贪心策略:和 LeetCode 435 无重叠区间是同一个意思
       const int n = points.size();
       if(n < 2) return n;
       std::sort(points.begin(), points.end(), cmp);//按气球的结束坐标大小,对升序排列
       int ans = 1;//不相交的气球个数 = 引爆全部气球需要的弓箭数量
       int tail = points[0][1];//前一个不相交的气球结束坐标
       for(int i = 1; i < n; ++i)
       {
    
           if(points[i][0] > tail)//不相交的条件:后一个气球的开始坐标大于(不能等于)前一个气球的结束坐标
           {
    
               ++ans;
               tail = points[i][1];
           }
       }
       return ans;
    }
};


    sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>&b){
    
        return a[1] < b[1];//这里a[0]<b[0]也能ac
    });

    int start = points[0][0];
    int end = points[0][1];
    int sum = 1;
    for(int i = 1; i < points.size(); i++) {
    
        if(points[i][0] > end || points[i][1] < start) {
    
            sum++;
            start = points[i][0];
            end = points[i][1];
        }
        else {
    
            start = max(start, points[i][0]);
            end = min(end, points[i][1]);
        }
    }

    return sum;
}

394 字符串解码

3[a2[c]]

推着入栈 pair(num,string)
首先是 3 然后 【 表示开始
记录3 和前面的字符串为空

记录下a ,
然后遇到了2,前面的字符串为a
pair 2,a
记录【 新的开始 c
遇到了结束
表示 2 前面有a 然后
a 与 两个 c
变成acc,
然后又遇到了结束,这一层是 3 与空字符
表示 这一层 空字符 加上 3个acc

    string decodeString(string s) {
    
	//两个栈分别压int res和用pair
	stack<pair<int, string>> sta;
	int num = 0; string res = "";
	//循环检查字符串
	for (int i = 0; i < s.size(); i++) {
    
		//遇到数字则存入num
		if (s[i] >= '0'&&s[i] <= '9') {
    
			num *= 10;
			num += (s[i] - '0');//这里括号是否需要
		}
		else if (s[i] == '[') {
    //遇到[压栈数字和字符串,置零置空
			sta.push(make_pair(num, res));
			num = 0;
			res = "";
		}
		else if (s[i] == ']') {
    //遇到]出栈数字和字符串,组装
			int n = sta.top().first;//n指示的是res的循环次数,不是a的
			string a = sta.top().second;
			sta.pop();
			for (int i = 0; i < n; i++)  a = a + res; //循环n次
			res = a;
		}
		else {
    //遇到字符存入字符
			res += s[i];
		}		
	}
	return res;
}

1331. 数组序号转换

https://blog.csdn.net/weixin_47138280/article/details/110548737

class Solution:
    def arrayRankTransform(self, arr: List[int]) -> List[int]:
        ranks = {
    v: i for i, v in enumerate(sorted(set(arr)), 1)}
        return [ranks[v] for v in arr]

首先是 set()类型转换
然后sorted 排序
enumerate遍历
返回的 序列号 i 和 元素v
构建键值对 v:i
构建【】,里面 循环遍历arr中的元素 v作为 键取出值,然后按顺序

class Solution {
    
public:
    vector<int> arrayRankTransform(vector<int>& arr) {
    
        set<int> s;
        for(int i=0;i<arr.size();i++)
        {
    
            s.insert(arr[i]);
        }
        for(int i=0;i<arr.size();i++)
        {
    
           set<int>::iterator pos= s.find(arr[i]);
           //int k= (int)(pos-s.begin());
           int k = distance(s.begin(),pos);
           arr[i]=++k; 
        }
        return arr;
        
    }
};
#include<numeric>
class Solution {
    
public:
    vector<int> arrayRankTransform(vector<int>& arr) {
    
        vector<int> idx(arr.size());
        iota(idx.begin(), idx.end(), 0);  赋值0到n
        sort(idx.begin(), idx.end(), [r = arr.data()](int a, int b){
    return r[a] < r[b];});
        这里已经是按照arr中的从小到大 对0到n排序了 相当于对idx排序,如果r[1]最小 r[0]最大 相当于
        【1230】  他题目中要求的是数字当前的位置
        int rk = 0, rear = INT_MIN;
        for(int x: idx){
                  遍历 idx中元素,相当于从小到大遍历 arr元素, arr【i】处的位置应当是当前第几个最小值,与上一个最小值相比,相等的话,该元素索引当前位置就变为相同的数,不然就是变为第几个最小的值
            if(arr[x] != rear) ++rk;      这里做的相当于核实校准 
            rear = arr[x]; 把这个值给到目前比较值 如果后面的值一样大 就不会rk++了
            arr[x] = rk;
        }
        return arr;
    }
};
iota(idx.begin(), idx.end(), 0); 对一个范围内进行赋值 从 0到n
这行代码使用了STL中的iota函数,它将起始点为0、步长为1的连续的整数填充到容器idx的迭代器范围内,其中idx.begin()为迭代器范围的起始位置,idx.end()为结束位置。简单来说,这行代码为idx中的每个元素赋值从0开始递增的连续整数。

  std::sort(idx.begin(), idx.end(), [&v](size_t i1, size_t i2) {
     return v[i1] < v[i2]; });

lambda语法

http://c.biancheng.net/view/3741.html
其中 capture 是捕获列表,params 是参数表,opt 是函数选项,ret 是返回值类型,body是函数体。
https://zhuanlan.zhihu.com/p/384314474

https://blog.csdn.net/u014072827/article/details/119736781

2359. 找到离给定两个节点最近的节点

n个节点 n-1条边
每个节点至多一条出边

设立一个长度为 n,值都是n 的 distance 表,
然后循环 只要 x不等于-1 并且他的dis 对应节点的距离没算出来
当前到达位置的距离给入 dis 并且 d+1 ,然后查看下一个节点。
x能到达点的距离都算出来了

for i,d1,d2 in zip(range(n),cal(node1),cal(node2))

node1 和node2 都能访问到的节点, 最小化一个最大值

class Solution {
    
public:
    vector<int> cal(vector<int> &edges ,int &node)
    {
    
        vector<int> dis(edges.size(), edges.size());
        int d=0;
        for(int i= node; i>=0 && dis[i]==edges.size();i=edges[i] )
        {
    
            dis[i] = d++;
            
        }
        return dis;
    }

    int closestMeetingNode(vector<int>& edges, int node1, int node2) {
    
        vector<int> dis1 =  cal(edges,node1);
        vector<int> dis2  =  cal(edges, node2);

        int ma =edges.size();
        int ans=-1;
        for(int i=0 ; i<dis1.size();i++)
        {
    
           int d =max(dis1[i],dis2[i]);
           if( d<ma)
           {
    
               ma =d;
               ans = i; 
           }
        }

        return ans;

    }
};

1380 矩阵中的幸运数

class Solution {
    
public:
    vector<int> luckyNumbers (vector<vector<int>>& matrix) {
    
        //int row = matrix.size();

        int max1=0;
        vector<int> ans;
        //int col = matrix[0].size();
        for(int i =0; i<matrix.size(); i++)
        {
    
            int rmin = *min_element(matrix[i].begin(),matrix[i].end());
            auto minPosition = min_element(matrix[i].begin(),matrix[i].end()) - matrix[i].begin();
            for(int j=0;j<matrix.size();j++)
            {
    
               max1=max(max1,matrix[j][minPosition]);
            }
            if(max1==rmin)
            ans.push_back(max1);
            max1=0;
        }
        return ans;
    }
};

找到离给定两个节点最近的节点

https://leetcode.cn/problems/find-closest-node-to-given-two-nodes/solution/by-lfool-t4y7/

class Solution {
    
public:
    int closestMeetingNode(vector<int> &edges, int node1, int node2) {
    
        int n = edges.size(), min_dis = n, ans = -1;    多少条边   
        auto calc_dis = [&](int x) -> vector<int> {
    
            vector<int> dis(n, n);			创建n个n的 vector
            for (int d = 0; x >= 0 && dis[x] == n; x = edges[x]) 
                dis[x] = d++;
            return dis;
        };

其实就是这个节点到每个节点的距离
上面做的就是设立一个函数  给到一个节点x,如果节点存在并且他的位置还是n说明没算过
 比方说[2,2,3,-1], 给了节点1,那么 创建节点1的dis vector
 满足1>=0 dis[1] ==n,  dis[1] =0; d=1
 然后 x = edges[1], 相当于到2了,x变成22满足,那么dis[2]1
 然后一路往下直到该路线的尽头
另一个节点同理 直到该路线的尽头

对于两个dis vector
这两个节点到一个节点的距离较大值最小
遍历两个vector的每个点的最大值, 就是两个节点都能到达的点的距离最小,然后返回ans

        auto d1 = calc_dis(node1), d2 = calc_dis(node2);
        for (int i = 0; i < n; ++i) {
    
            int d = max(d1[i], d2[i]);
            if (d < min_dis) {
    
                min_dis = d;
                ans = i;
            }
        }
        return ans;
    }
};

作者:endlesscheng
链接:https://leetcode.cn/problems/find-closest-node-to-given-two-nodes/solution/ji-suan-dao-mei-ge-dian-de-ju-chi-python-gr2u/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

830. 较大分组的位置

他这里处理的比我巧妙
if (i == n - 1 || s[i] != s[i + 1]) {


class Solution {
    
public:
    vector<vector<int>> largeGroupPositions(string s) {
    
        vector<vector<int>> ret;
        int n = s.size();
        int num = 1;
        for (int i = 0; i < n; i++) {
    
            if (i == n - 1 || s[i] != s[i + 1]) {
    
                if (num >= 3) {
    
                    ret.push_back({
    i - num + 1, i});
                }
                num = 1;
            } else {
    
                num++;
            }
        }
        return ret;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/positions-of-large-groups/solution/jiao-da-fen-zu-de-wei-zhi-by-leetcode-so-fi3n/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    
public:
    vector<vector<int>> largeGroupPositions(string s) {
    
    vector<vector<int>> ans;
    vector<int> idx;
    int num=1;
    //char pre = s[0];
    for(int i=0; i<s.size()-1;i++)
    {
    
        if(s[i]==s[i+1])
        {
    
            num++;
            idx.push_back(i);
            if(i+1 ==s.size()-1 && num>=3)    这里就是两个两个比   然后这里的if其实就是判断防止最后的遗漏,因为如果没,我是要不相等了他才会加入, 这里就是防止一直是相等的 然后到最后了,给他加入
            {
    
                int beg =idx[0];
               int end =idx[idx.size()-1]+1;
               idx={
    };
               idx.push_back(beg);
               idx.push_back(end); 
               ans.push_back(idx); 
            }
        }
        else
        {
    
            if(num>=3)
            {
    
               int beg =idx[0];
               int end =idx[idx.size()-1]+1;
               idx={
    };
               idx.push_back(beg);
               idx.push_back(end); 
               ans.push_back(idx); 
            }
            num=1;
            idx={
    };
        
        }
    }
    return ans;
    }
};






    vector<vector<int>> largeGroupPositions(string s) {
    
        vector<vector<int>> ans;
        vector<int> idx;

        if(s.length()<3)
        return ans;
        for(int i=0; i< s.length()-2; i++)
        {
    
            if(s[i]== s[i+1] && s[i+1] == s[i+2])
            {
    
                int beg =i;
                int add = 2;
                while(i+add <s.length() && s[i+2]==s[i+add+1])
                {
    
                    add++;
                }

                ans.push_back({
    i,i+add});
                i= i+add;
            }

        }
        return ans;
    }

小米

参考leecode
https://leetcode.cn/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/solution/mian-shi-ti-68-ii-er-cha-shu-de-zui-jin-gong-gon-7/

在这里插入图片描述

class Solution {
    
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
        if (root == null || p == root || q == root) {
    
            return root;
        }

        TreeNode l = lowestCommonAncestor(root.left, p, q);
        TreeNode r = lowestCommonAncestor(root.right, p, q);
    
        return l == null ? r : (r == null ? l : root);
    }
}
class Solution {
    
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
        if(!root||root==p||root==q) return root;
        TreeNode* l = lowestCommonAncestor(root->left, p, q);
        TreeNode* r = lowestCommonAncestor(root->right, p, q);
        return l?(r?root:l):r;
    }

};



code block
class Solution {
    
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
        //1.如果找不到p或q就返回null,如果找的到就返回该点 ps:我觉得return root设计的很巧妙
        if(root == null || root == p || root == q) return root; 
        //2.如果左子树中有p或q,那么就会返回找到的点。或者p和q都有,就返回pq的公共点。或者p或q都没有就返回null。
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        //3.如果右子树中有p||q,那么就会返回找到的点。或者p和q都有,就返回pq的公共点。或者p或q都没有就返回null。
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        //4.left==null 说明:左子树中没有p或q(往上看最开始的判断语句:找不到就返回null)
        // 5.直接返回right的原因,需要结合递归的思想多方面思考。
        if(left == null) return right;
        //6.运行到此处说明左子树中找到了p或q点。
        if(right == null) return left;
        //7.运行到此处说明p和q都找到了,root为最近的公共祖先。(该语句只会运行一次)
        return root;
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/MakeYouClimax/article/details/129509334

智能推荐

(3)组合数学--鸽巢原理之最简单形式_鸽巢原理的三个公式-程序员宅基地

文章浏览阅读220次。定理:把n+1个物体放进n个盒子中,至少有一个盒子中含有两个物体理解:ai为第i天下的总棋盘数,显然an为递增序列,对an做部分和序列:如上图所示,上面77项,下面77项,共154项,153个盒子,所有存在aj+21 = ai,所以21 = aj - ai = bi + bi+1 + … + bj相当于19个物体,18个盒子五个点,四个三角形反证:Li <..._鸽巢原理的三个公式

Qt开发笔记之QCustomPlot:QCustomPlot介绍、编译与使用_qcustomplot编译-程序员宅基地

文章浏览阅读6.6w次,点赞20次,收藏194次。欢迎技术交流和帮助,提供所有IT相关的服务,有需要请联系博主QQ: 21497936,若该文为原创文章,未经允许不得转载原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/77847820目录效果 ​Demo下载地址QCustom..._qcustomplot编译

微信小程序的动态显示字体颜色_小程序 color if-程序员宅基地

文章浏览阅读1k次。<text wx:if="{{item.data.status=='待打印'}}" style="color:red">{{item.data.status}}</text><text wx:if="{{item.data.status=='已打印'}}" style="color:green">{{item.data.status}}</text>_小程序 color if

线上PHP问题排查思路与实践-程序员宅基地

文章浏览阅读210次。转载:http://www.bo56.com/%E7%BA%BF%E4%B8%8Aphp%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E6%80%9D%E8%B7%AF%E4%B8%8E%E5%AE%9E%E8%B7%B5/前几天,在一淘网,腾讯网媒和微博商业技术联合组织的技术分享大会上,我分享了《在线PHP问题排查思路与实践》。此博文除了对PPT..._在php开发过程中,线上代码怎么查哪段代码有问题,且不影响线上运行

linux 内核升级-程序员宅基地

文章浏览阅读841次,点赞28次,收藏9次。centos 7.x 升级内核 3.x 至 5.x

去掉java文件中的注释_利用JavaParser去除java文件中的注释-程序员宅基地

文章浏览阅读922次。利用JavaParser去除java文件中的注释个人博客:记录一下在项目实施过程中的一些点情景回顾之前项目有个需求,就是去掉.java文件中的所有注释,常用的方法是用正则匹配。然而在网络上查找到的正则或多或少都有一些问题,无法匹配到所有的情况。或者说,由于写.java文件的人的不规范(各种奇葩的问题),导致正则覆盖不全。所以正则方法不靠谱,或者说,存在一定的限制。新的想法后来想到利用AST来去除注..._在线java代码去除注释工具

随便推点

【MaixPy快速上手】屏幕和摄像头的使用_maixpy reset failed-程序员宅基地

文章浏览阅读1.3k次。第一个程序: 使用屏幕和摄像头开发板有配套的摄像头和屏幕,请在上电前检查硬件连接是否正确然后上电,打开串口终端, 按键盘Ctrl+E,然后粘贴以下代码:import sensor, lcdsensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.run(1)sensor.skip_frames()lcd.init(freq=15000000)while(True)_maixpy reset failed

【系统性学习】Linux Shell易忘重点整理_shell赋值保留换行-程序员宅基地

文章浏览阅读1.1k次。本文主要基于《实用Linux Shell编程》总结,并加入一些网上查询资料和博主自己的推断。其中命令相关的,已抽取出来在另一篇中,可以一起使用。_shell赋值保留换行

构造函数和析构函数-程序员宅基地

文章浏览阅读4.2k次,点赞10次,收藏25次。构造函数、初始化列表、析构函数_构造函数和析构函数

分布式架构知识体系-程序员宅基地

文章浏览阅读281次。1.问题 1、何为分布式何为微服务? 2、为什么需要分布式? 3、分布式核心理论基础,节点、网络、时间、顺序,一致性? 4、分布式是系统有哪些设计模式? 5、分布式有哪些类型? 6、如何实现分布式? 2.关键词节点,时间,一致性,CAP,ACID,BASE,P2P,机器伸缩,网络变更,负载均衡,限流,鉴权,服务发现,服务编排,降级,熔断,幂等,分库分表,分片分区,自动运维,容错处理,全栈监控,故障恢复,性能调优3.全文概要随着移动互联网_分布式架构知识体系

深信服AF防火墙配置SSL VPN_深信服ssl配置教程-程序员宅基地

文章浏览阅读1.5k次,点赞6次,收藏13次。深信服防火墙配置SSL VN_深信服ssl配置教程

linux系统rabbitmq安装步骤_rabbitmq linux安装-程序员宅基地

文章浏览阅读768次。一、安装erlang:1、先下载rpm包:wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm2、rpm包:rpm -Uvh erlang-solutions-1.0-1.noarch.rpm可能会有以下问题:解决办法:(执行以下命令后,在执行上一条命令)yum..._rabbitmq linux安装

推荐文章

热门文章

相关标签