Analysis of Leetcode Problem Solving Ideas (37) 307-316

  1. Area and retrieval-array can be modified

A very simple question

class NumArray {
    
    
        vector<int> m_sum;
        vector<int> m_nums;
public:
    NumArray(vector<int>& nums) {
    
    
        m_nums = nums;
        m_sum = nums;

        if (nums.size() == 0) 
            return;

        for (int i = 1; i < nums.size(); i++)
        {
    
    
            m_sum[i] += m_sum[i - 1];
        }
    }
    
    void update(int i, int val) {
    
    
        int dif = val - m_nums[i];
        m_nums[i] = val;

        for (int j = i; j < m_sum.size(); j++)
        {
    
    
            m_sum[j] += dif;
        }
    }
    
    int sumRange(int i, int j) {
    
    
        if (i == 0)
            return m_sum[j];
        else
            return m_sum[j] - m_sum[i - 1];
    }
};

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray* obj = new NumArray(nums);
 * obj->update(i,val);
 * int param_2 = obj->sumRange(i,j);
 */
  1. The best time to buy and sell stocks includes the freezing period.
    Given an integer array, the i-th element represents the stock price on the i-th day.
    Design an algorithm to calculate the maximum profit. Under the following constraints, you can complete as many transactions as possible (buying and selling a stock multiple times):
    You cannot participate in multiple transactions at the same time (you must sell the previous stock before buying again).
    After selling the stock, you cannot buy the stock the next day (ie, the freezing period is 1 day)

Classic dynamic programming application. First write down the relationship between the state on day I and day i-1, and then perform dimensionality reduction optimization.

class Solution {
    
    
public:
    int maxProfit(vector<int>& prices) {
    
    
        if (prices.empty()) {
    
    
            return 0;
        }

        int n = prices.size();
        int f0 = -prices[0];
        int f1 = 0;
        int f2 = 0;
        for (int i = 1; i < n; ++i) {
    
    
            int newf0 = max(f0, f2 - prices[i]);
            int newf1 = f0 + prices[i];
            int newf2 = max(f1, f2);
            f0 = newf0;
            f1 = newf1;
            f2 = newf2;
        }

        return max(f1, f2);
    }
};
  1. Minimum height tree
    For an undirected graph with tree characteristics, we can choose any node as the root. Graphs can therefore become trees. Among all possible trees, the tree with the smallest height is called the smallest height tree. Given such a graph, write a function to find all the minimum height trees and return their root nodes.

The main point of this question is that if the minimum height tree uses the leaf of the graph as the root, the other points to the leaf are at least 1 + leaf parent node. It can be seen that leaf nodes are not our option. Move closer to the middle from all the leaf nodes, and recursively peel them layer by layer until they meet, which is the intersection with the shortest distance. Depending on the depth, the odd and even number may be 1 result or 2 results

class Solution {
    
    
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
    
    
	if (n == 1)
		return {
    
     0 };
	else if (n == 2)
		return{
    
     0,1 };

	vector<int> indegree(n,0);//入度数组,并初始化
	vector<int> v;
	vector<vector<int>> graph(n,v);//图形表示,并初始化
	for (int i = 0; i < edges.size(); i++)//构造图与入度数组:无向图,两个点都要处理
	{
    
    
		graph[edges[i][0]].push_back(edges[i][1]);
		graph[edges[i][1]].push_back(edges[i][0]);
		indegree[edges[i][0]]++;
		indegree[edges[i][1]]++;
	}
	queue<int> myqueue;//装载入度为1的queue
	for (int i = 0; i < n; i++)
	{
    
    
		if (indegree[i] == 1)
			myqueue.push(i);
	}
	int cnt = myqueue.size();//!!令cnt等于myqueue.size(),一次性将入度为1的点全部删去。
	while (n>2)
	{
    
    
		n -= cnt;//一次性将入度为一的点全部删去!!不能一个一个删!
		while (cnt--)
		{
    
    
			int temp = myqueue.front();
			myqueue.pop();
			indegree[temp] = 0;
			//更新temp的邻接点:若temp临接点的入度为1,则将其放入queue中。
			for (int i = 0; i < graph[temp].size(); i++)
			{
    
    
				if (indegree[graph[temp][i]] != 0)
				{
    
    
					indegree[graph[temp][i]]--;
					if (indegree[graph[temp][i]] == 1)//放在这里做!只判断邻接点。
						myqueue.push(graph[temp][i]);
				}
				
			}
		}
		cnt = myqueue.size();
	}
	vector<int> result;
	while (!myqueue.empty())
	{
    
    
		result.push_back(myqueue.front());
		myqueue.pop();
	}
	return result;
}
};

  1. Poke balloons
    There are n balloons, numbered from 0 to n-1. Each balloon is marked with a number, and these numbers are stored in the array nums.

Now you are required to pop all the balloons. If you pop the balloon i, you can get nums[left] * nums[i] * nums[right] coins. Here left and right represent the serial numbers of the two balloons adjacent to i. Note that when you burst the balloon i, the left and right balloons become adjacent balloons.
Find the maximum number of coins that can be obtained.

Classical dynamic programming problems can be solved by top-down or bottom-up thinking. Core idea: If it is to poke a balloon, poke the smallest inner balloon first, and poke the edge last. If you add balloons, add them from the larger one

class Solution {
    
    
public:
    int maxCoins(vector<int>& nums) {
    
    
        int n = nums.size();
        vector<vector<int>> rec(n + 2, vector<int>(n + 2));
        vector<int> val(n + 2);
        val[0] = val[n + 1] = 1;
        for (int i = 1; i <= n; i++) {
    
    
            val[i] = nums[i - 1];
        }
        for (int i = n - 1; i >= 0; i--) {
    
    
            for (int j = i + 2; j <= n + 1; j++) {
    
    
                for (int k = i + 1; k < j; k++) {
    
    
                    int sum = val[i] * val[k] * val[j];
                    sum += rec[i][k] + rec[k][j];
                    rec[i][j] = max(rec[i][j], sum);
                }
            }
        }
        return rec[0][n + 1];
    }
};


  1. Super ugly number
    Write a program to find the nth super ugly number.
    A super ugly number means that all prime factors are positive integers in primes, a list of prime numbers of length k.

1) The source of the elements of the queue: top element * list of prime numbers, put the newly generated elements into the queue, and the nth element that pops up is the super ugly number we want. However, the popped element is not necessarily the n-th smallest prime number, so we need to sort it before popping.
2) For the nth prime number, the queue is required to be ordered and arranged from small to large, so we take the small top pile

class Solution {
    
    
public:
    int nthSuperUglyNumber(int n, vector<int> &primes)
    {
    
    
        priority_queue<long long, vector<long long>, greater<long long>> buff;
        unordered_set<long long> primeset;

        buff.push(1);
        primeset.insert(1);
        long long i = 1;
        int count = 0;
        while (count < n) {
    
    
            count++;
            i = buff.top();
            buff.pop();
            for (long long prime : primes) {
    
    
                long long next = i * prime;
                if (next<=INT32_MAX && !primeset.count(next)) {
    
    
                    buff.push(next);
                    primeset.insert(next);
                }
            }
        }

        return i;
    }
};

  1. Calculate the number of elements on the right side that are less than the current element.
    Given an integer array nums, return a new array counts as required. The array counts has this property: the value of counts[i] is the number of elements on the right side of nums[i] that are less than nums[i].

This problem is solved by a tree array, which is a classic problem. It can be understood that each bucket stores a number of values, and then can be accumulated

class Solution {
    
    
private:
    int lowbit(int x){
    
    
        return x & (-x);
    }
    void update(int i, vector<int>&C){
    
    
        while (i < C.size()) {
    
    
            C[i]++;
            i += lowbit(i);
        }
    }
    void query(int i, int j, vector<int>&C, vector<int>&counts){
    
    
        while (i >= 1) {
    
    
            counts[j] += C[i];
            i -= lowbit(i);
        }
    }
public:    
    vector<int> countSmaller(vector<int>& nums) {
    
    
        vector<int>counts(nums.size(), 0);
        if (nums.size() < 1) {
    
    
            return counts;
        }
        
        vector<int>N(nums);
        // Sort and unique
        sort(N.begin(), N.end());
        int slow = 1;
        int fast = 1;
        while(fast< N.size()) {
    
    
            if (N[fast] != N[slow - 1]) {
    
    
                N[slow] = N[fast];
                slow++;
                fast++;
            }else{
    
    
                fast++;
            }
        }
        N.resize(slow);
        
        // key: number, value: i
        map<int, int>m;
        for (int j = 1; j < 1 + N.size(); ++j) {
    
    
            m[N[j - 1]] = j;
        }
        
        // traverse
        vector<int>C(N.size() + 1, 0); //  C[i] is necessary, but A[i] not
        int i;
        for (int j = nums.size() - 1; j >= 0; --j) {
    
    
            i = m[nums[j]];
            update(i, C);
            if (i != 1) {
    
    
                query(i - 1, j, C, counts);
            }else{
    
    
                counts[j] = 0;
            }
        }
        return counts;
    }
};

  1. Remove Repeated Letters
    Give you a string containing only lowercase letters. Please remove the repeated letters in the string so that each letter appears only once. It is necessary to ensure that the lexicographic order of the returned result is the smallest (required not to disturb the relative position of other characters).

If you want to minimize the lexicographic order of the result, you should keep small elements in front as much as possible. If the element at the top of the stk stack is greater than the element currently traversed, according to the above principles, this situation should be avoided if conditions permit. According to the requirements of the topic (de-duplication), only if there is an element on the top of the stack later In order to remove the top element of the stack (reduce a reverse order). If there is no such element on the top of the stack later, it can only be kept here, even if it is larger than its next element.

class Solution {
    
    
public:
    string removeDuplicateLetters(string s) {
    
    
        string stk;
        size_t i = 0;
        for(size_t i = 0;i < s.size(); ++i)
        {
    
    
            if(stk.find(s[i]) != string::npos) continue;
            while(!stk.empty()&& stk.back() > s[i]&& 
                s.find(stk.back(), i) != string::npos)
                stk.pop_back();
            stk.push_back(s[i]);
        }
        return stk;
    }
};

Guess you like

Origin blog.csdn.net/u013354486/article/details/107955001