### Article directory

# 738. Monotonically Increasing Numbers

An integer is said to be monotonically increasing if and only if the number x and y in each adjacent digit satisfies x <= y.

Given an integer n, returns the largest number less than or equal to n that increases monotonically.

Example 1:

```
输入: n = 10
输出: 9
```

Example 2:

```
输入: n = 1234
输出: 1234
```

Example 3:

```
输入: n = 332
输出: 299
```

**Ideas:**

The first step is to find the global optimum:

**find <=nthe largest monotonically increasing integer**

The second step is to find the optimal solution to the sub-problem:

Sub-problem: Find the maximum incremental number that meets the conditions for two adjacent numbers

①Example

For example: 98, once the previous digit is larger than the latter digit `s[i - 1] > s[i]`

, let `s[i - 1]--`

, and then `s[i]`

change it to 9, that is, the integer 89 is the largest monotonically increasing integer smaller than 98.

Local optimum:

For two adjacent numbers, `s[i - 1] > s[i]`

, let `s[i - 1]--`

, `s[i]`

be assigned as 9, which can ensure that these two digits become the largest monotonically increasing integer.

When the local optimum is derived from the global optimum, the traversal order must also be considered, and the bit from which the mark starts is uniformly changed to 9.

If it goes from front to back, counterexample 322 (322->292->289) will change the results that have been traversed, so **it should be** traversed from back to front.

After determining the traversal order, imagine if there are any counterexamples. If not, you can try to be greedy:

```
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string s = to_string(n);
int flag = s.size();
for (int i = s.size() - 1; i > 0; i--) {
if (s[i - 1] > s[i] ) {
flag = i;
s[i - 1]--;
}
}
for (int i = flag; i < s.size(); i++) {
s[i] = '9';
}
return stoi(s);
}
};
//时间复杂度O(n)
```

# 435. Non-overlapping Intervals (Activity Scheduling Problem)

Given a set intervals of intervals, where intervals[i] = [starti, endi]. Returns the minimum number of intervals that need to be removed such that the remaining intervals do not overlap.

Example 1:

```
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
```

Explanation: After removing [1,3], the remaining intervals do not overlap.

Example 2:

```
输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
```

Explanation: You need to remove both [1,2] to make the remaining intervals non-overlapping.

Example 3:

```
输入: intervals = [ [1,2], [2,3] ]
输出: 0
```

Explanation: You don't need to remove any intervals, since they are already non-overlapping.

The first step is to find the global optimum:

**find the most non-overlapping intervals**

The second step is to find the optimal solution to the subproblem:

**sorting**

strategy:

~~Sort by smallest interval difference~~- Sort by the value at the beginning of the range
- Sort by range end value

Local Optimum:

Method 1: **Sorting according to the end value of the interval.** The steps of the greedy algorithm are as follows:

- n intervals sorted by end value
- Select the first interval that ends, and delete (or skip) the next interval that conflicts with it
- Repeat the previous step until the interval is empty.

```
class Solution {
public:
static bool cmp (const vector<int>& a, const vector<int>& b) {
return a[1] < b[1];
}
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.size() == 0) return 0;
sort(intervals.begin(), intervals.end(), cmp);
int count = 1;
int lastend = intervals[0][1]; // 区间的结束位置
for (int i = 1; i < intervals.size(); i++) {
if (lastend <= intervals[i][0]) {
lastend = intervals[i][1];
count++;
}
}
return intervals.size() - count;
}
};
//时间复杂度：O(nlog n)
```

Method 2: **Sort according to the start value of the interval** , and traverse in reverse order to delete conflicting intervals.

# 134. Gas station

There are n gas stations on a loop, and the i-th gas station has gas[i] liters of gasoline.

You have a car with unlimited fuel tank capacity, and it takes cost[i] liters of gasoline to drive from the i-th gas station to the i+1-th gas station. You start off from one of the gas stations, starting with an empty tank.

Given two integer arrays gas and cost, return the number of the gas station at the time of departure if you can travel around the circle, otherwise return -1. If a solution exists, it is guaranteed to be unique.

**Example 1:**

```
输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
输出: 3
```

**Explanation:**

Starting from gas station No. 3 (index 3), you can get 4 liters of gasoline. At this time, the fuel tank has = 0 + 4 = 4 liters of gasoline

. Go to gas station No. 4. At this time, the fuel tank has 4 - 1 + 5 = 8 liters of gasoline.

Go to No. 0 gas station, and the fuel tank has 8 - 2 + 1 = 7 liters of gasoline Go

to No. 1 gas station, at this time the fuel tank has 7 - 3 + 2 = 6 liters of gasoline

Go to No. 2 gas station, at this time the fuel tank has 6 - 4 + 3 = 5 liters of gasoline

Go to No. 3 gas station, you It takes 5 liters of petrol, just enough to get you back to gas station #3.

Therefore, 3 can be the starting index.

**Idea: **

The first step is to find the global optimum:

**find the starting position where you can run around**

The second step is to find the optimal solution to the subproblem:

It is known that only when **the sum of fuel at the gas station >= the sum of all fuel consumption** , can one complete a lap (there must be a solution)

=> `rest[i]`

the sum of the remaining fuel must be greater than or equal to zero

i starts to accumulate rest[i] from 0, and the sum is recorded as curSum. Once curSum is less than zero, it means that the interval [0, i] cannot be used as the starting position. The starting position is calculated from i+1, and then curSum is calculated from 0.

**Local optimum** : The starting position of the

**current accumulated rest[i]sum curSum<=0must be at least j+1, because starting from j must not work.**

The local optimum can lead to the global optimum, and no counterexample can be found, try greedy:

```
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int totalSum = 0;
int start = 0;
for (int i = 0; i < gas.size(); i++) {
curSum += gas[i] - cost[i];
totalSum += gas[i] - cost[i];
if (curSum < 0) {
// 当前轮累加rest[i]和 curSum小于0，开启下一轮
start = i + 1;
curSum = 0;
}
}
if (totalSum < 0) return -1; // rest[i]之和小于0无结果
return start;
}
};
// 时间复杂度：O(n)
```

Method 2: Simulation of Global Optimal Consideration

```
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int min = INT_MAX; // 从起点出发，油箱里的油量最小值
for (int i = 0; i < gas.size(); i++) {
int rest = gas[i] - cost[i];
curSum += rest;
if (curSum < min) {
min = curSum;
}
}
if (curSum < 0) return -1; // 情况一：如果gas的总和小于cost总和，那么无论从哪里出发，一定是跑不了一圈的
if (min >= 0) return 0; // 情况二：rest[i] = gas[i]-cost[i]为一天剩下的油，i从0开始计算累加到最后一站，
//如果累加没有出现负数，说明从0出发，油就没有断过，那么0就是起点。
// 情况三：如果累加的最小值是负数，汽车就从非0节点出发，从后向前，看哪个节点能把负数
// 填平，能把这个负数填平的节点就是出发节点。
for (int i = gas.size() - 1; i >= 0; i--) {
int rest = gas[i] - cost[i];
min += rest;
if (min >= 0) {
return i;
}
}
return -1;
}
};
//O（n）
```