leetcode

最近稍閒,就刷leetcode玩,說是爲了準備找工做,其實就是好玩,由於好水啊哈哈哈哈。node

混了個國獎,感受我乾的像樣一點的事情都跟我無關,因此仍是,努力讓本身變成一個更好的人吧。c++

從今天起就記錄一下我沒有1A或者有意思的題目吧。算法

2015.10.16ide

Contains Duplicate IIIspa

Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.c++11

class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        multiset<int> m;
        for (int i = 0;i<nums.size();i++)
        {
            if (i>=k+1) m.erase(nums[i-k-1]);
            auto lb = m.lower_bound(nums[i]-t);
            if (lb != m.end() && (*lb)-t<=nums[i]) return true;
            m.insert(nums[i]);
        }
        return false;
    }
};

沒有1A的緣由:nums[i]+t會超int,好吧,相似還有一個二分題中間,m=(l+r)/2也會超過int。順便記一下,INT_MAX, INT_MIN, 記得想一想就好。code

這道題目的想法仍是挺直觀的,只是發現用stl寫,真的好省事。orm

 Max Points on a Lineblog

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.遞歸

class Solution {
public:
    int maxPoints(vector<Point>& points) {
        int ret = 0;
        for (auto &i : points)
        {
            unordered_map<long double,int> m;
            int dup = 0;
            for (auto& j : points)
            {
                if (i.x == j.x && i.y == j.y) dup++;
                else
                {
                    if (i.x == j.x) m[INFINITY]++;
                    else m[((long double)i.y - j.y)/((long double)i.x - j.x)]++;
                }
            }
            int localMax = 0;
            for (auto &x : m) localMax = max(localMax,x.second);
            localMax += dup;
            ret = max(ret,localMax);
        }
        return ret;
    }
};

也是感嘆一下 STL讓程序變的更加美觀

還有for循環,最近接觸了c++11的寫法

 

10.23

Best Time to Buy and Sell Stock IV

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most k transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

這道題目仍是有點意思的

比較容易想到動態規劃, f[k][n]表示k次交易在前n天的最大收益

f[k][n] = max{f[k-1][n],f[k][n-1],max{f[k-1][p] - a[p+1] + a[n]} }

直接這樣是O(k*n^2), 能夠後面那一項存下來,理解爲持多倉一手的最大收益。

貼個

class Solution {
public:
    int maxProfit(int k, vector<int>& a) {
        int Len = a.size();
        if (!Len || !k) return 0;
        
        //
        if (k >= Len/2)
        {
            int ret = 0;
            for (int i = 0;i<Len-1;i++)
            if (a[i] < a[i+1]) ret+= a[i+1] - a[i];
            return ret;
        }
        //
        
        vector<vector<int>> f = vector<vector<int>>(2,vector<int>(Len,0));
        for (int i = 1;i<=k;i++)
        {
            int maxLong = -a[0];
            for (int j = 1;j<Len;j++)
            {
                int i1 = i & 1;
                f[i1][j] = max(f[1-i1][j],f[i1][j-1]);
                f[i1][j] = max(f[i1][j],maxLong + a[j]);
                maxLong = max(maxLong,f[1-i1][j-1] - a[j]);
            }
        }
        return f[k&1][Len-1];
    }
};

還有O(n)算法

最優的交易策略必定是在極小值點買入,在極大值點賣出的

預處理能夠獲得全部波谷波峯對$(v_i,p_i)$,注意能夠捨去第一個波峯和最後一個波谷

若是不限制交易的次數,那麼能夠獲得每一個$(v_i,p_i)$對的收益$\sum(p_i-v_i)$

限制了交易的次數,有些波動是吃不到的,最好能吃到最大的k個向上波動

爲了讓選取最大的k個波動的算法可行,必須消除兩對(v,p)間的相互影響

對於前後出現的兩對$(v_i,p_i)$, $(v_j,p_j)$, 若是$v_i >= v_j$ 那麼最優的策略不可能$v_i$買入之後到$v_j$尚未賣出, 由於在$v_j$買入不會比$v_i$買入等到$v_j$多花錢,因此這兩個對是不相互影響的

精髓:

若是$p_j>p_i$, 那麼若是多一次交易機會,能夠多吃到$(p_i - v_j)$這個利潤

能夠等價成$(v_j,p_i)$ ,$(v_i ,p_j)$兩個對,若是隻有一次機會, 就作進大的這一對, 若是多一次交易機會, 就把小的利潤也作進去.

具體實現用到了棧

貼:

class Solution {
public:

    stack<pair<int,int>> st;

    int maxProfit(int k, vector<int>& a) {
        int v = 0;
        int p = 0;
        int Len = a.size();
        vector<int> pro;
        
        while (v < Len)
        {
            while (v+1 < Len && a[v+1]<=a[v]) v++;
            p = v+1;
            if (p == Len) break;
            while (p+1 < Len && a[p+1]>=a[p]) p++;
            int av = a[v];
            int ap = a[p];
            v = p+1;
            
            while (!st.empty() && av <= st.top().first)
            {
                pro.push_back(st.top().second - st.top().first);
                st.pop();
            }
            while (!st.empty() && ap > st.top().second)
            {
                pro.push_back(st.top().second - av);
                av = st.top().first;
                st.pop();
            }
            st.push({av,ap});
        }
        
        while (!st.empty())
        {
            pro.push_back(st.top().second - st.top().first);
            st.pop();
        }
        
        sort(pro.begin(),pro.end(),[](int a,int b){return a>b;});
        int ret = 0;
        if (k>pro.size()) k = pro.size();
        for (int i = 0;i<k;i++)
        ret+=pro[i];
        return ret;
    }
};

Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up:
Can you solve it without using extra space?

貼個代碼吧,記住就好,挺有意思的算法

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (!head) return NULL;
        auto p = head;
        auto q = head;
        int cnt = 0;
        for (;;)
        {
            cnt++;
            
            p = p->next;
            
            q = q->next;
            if (!q) return NULL;
            q = q->next;
            if (!q) return NULL;
            if (p == q) break;
        }
        p = head;
        while (p!=q)
        {
            p = p->next;
            q = q->next;
        }
        return p;
    }
};

10.24

Word Break II

Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.

Return all such possible sentences.

For example, given
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].

A solution is ["cats and dog", "cat sand dog"].

class Solution {
public:
    map<string,vector<string>> m;

    vector<string> combine(const string& s,vector<string> vs)
    {
        if (vs.size()==1 && vs[0] == ""){return vector<string>{s};}
        vector<string> ret;
        for (auto& x : vs)
        ret.push_back(s + " " + x);
        return ret;
    }
    
    vector<string> wordBreak(string s, unordered_set<string>& Dict) {
        vector<string> ret;
        if (s == "")
        {
            ret.push_back(s);
            return ret;
        }
        if (m.find(s)!=m.end()) return m[s];
        for (int i = 1;i<=s.length();i++)
        if (Dict.count(s.substr(0,i)))
        {
            auto tmp =combine(s.substr(0,i),wordBreak(s.substr(i,s.length()-i),Dict));
            ret.insert(ret.end(),tmp.begin(),tmp.end());
        }
        m[s] = ret;
        return ret;
    }
};

再次感嘆一下STL的強大,感受STL讓程序更加簡潔,易懂。這個程序不用STL的話,是很是冗長的。

Clone Graph

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.


OJ's undirected graph serialization:
Nodes are labeled uniquely.

We use # as a separator for each node, and , as a separator for node label and each neighbor of the node.
As an example, consider the serialized graph {0,1,2#1,2#2,2}.

The graph has a total of three nodes, and therefore contains three parts as separated by #.

First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
Second node is labeled as 1. Connect node 1 to node 2.
Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle.
貼:

class Solution {
public:
   unordered_map<UndirectedGraphNode*,UndirectedGraphNode*> m;
    
    UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
        if (!node) return node;
        if (m.find(node) != m.end()) return m[node];
        auto ret = new UndirectedGraphNode(node->label);
        m[node] = ret;
        for (auto& x : node->neighbors)
        ret->neighbors.push_back(cloneGraph(x));
        return ret;
    }
};

STL+遞歸,不談了。

相關文章
相關標籤/搜索