Categories
木有技术

LeetCode 403. Frog Jump

A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.
Given a list of stones’ positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.
If the frog’s last jump was k units, then its next jump must be either k – 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.
思路:这个题目可以看作是动态规划。青蛙的一个状态可以表示为{当前的k,当前的位置(可以用stone的索引表示)},最初的时候状态就是{ 1, 0 }。在某一个状态下,青蛙可以尝试向前移动{k-1, k, k+1}步,如果能成功跳到那就进入了下一个状态。要注意的是这种状态的遍历是有重复的,所以需要一个东西记录已经尝试过(当然是尝试失败的,不然直接return true)的状态们,不然很容易超时。
为了避免栈溢出,下文的解法直接用stack模拟函数的栈调用。

class Solution {
public:
    bool canCross(vector<int>& stones) {
        if (stones.empty())
            return false;
        else if (stones.size() == 1)
            return true;
        // state { k, index, has_traversed }
        stack<tuple<int, int, bool>> states;
        unordered_map<int, set<int>> visited;
        states.push({ 1, 0, false });
        while (!states.empty())
        {
            if (std::get<2>(states.top()) == true)
            {
                // pop state (like recursive function returning)
                states.pop();
                continue;
            }
            int last_k = std::get<0>(states.top());
            int last_pos_idx = std::get<1>(states.top());
            if (visited[last_k].count(last_pos_idx) > 0)
            {
                // avoid duplicated state entry
                states.pop();
                continue;
            }
            std::get<2>(states.top()) = true;
            visited[last_k].insert(last_pos_idx);
            if (last_pos_idx == stones.size() - 1)
                return true;
            for (int step = last_k - 1; step <= last_k + 1; ++step)
            {
                if (step == 0) continue;
                if (last_pos_idx == 0 && step != 1) continue; // can only move 1 step at the beginning
                int next_stone = stones[last_pos_idx] + step;
                for (int j = last_pos_idx + 1; j < stones.size(); ++j)
                {
                    if (stones[j] > next_stone) break;
                    if (stones[j] == next_stone)
                    {
                        states.push({ step, j , false}); //Push state of the next stone
                    }
                }
            }
        }
        return false;
    }
};

 

Categories
不学无术

LeetCode 432. All O`one Data Structure

几万年没做LeetCode的题了,更新一下。
https://leetcode.com/problems/all-oone-data-structure/description/
这道题的思路是用一个双向链表(list)来存储一个以value排序的数据结构,使用哈希表(unordered_map)来存储key到链表iterator的映射:

需要注意特殊处理value=1的Node的情况。
代码写得比较毛糙,但是确实是O(1)的复杂度,如果要优化的话map的插入可以用emplace()之类的。
注意:除了value=1的节点,其余节点的keys为空的时候要把该节点删除掉,否则getMaxKey()和getMinKey()就需要O(n)的遍历操作了。

struct KvNode
{
    unordered_set<string> keys;
    int value = 1;
};
class AllOne {
private:
    list<KvNode> value_key;     // arranged by val in ascending order
    using list_it_t = list<KvNode>::iterator;
    unordered_map<string, list_it_t> val_map;
    list_it_t init_node;    //node with value one
public:
    /** Initialize your data structure here. */
    AllOne() {
        value_key.push_back(KvNode());
        init_node = value_key.begin();
    }
    /** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */
    void inc(const string& key) {
        if (val_map.find(key) == val_map.end())
        {
            // `create' new node with value 1
            init_node->keys.insert(key);
            val_map[key] = init_node;
        }
        else
        {
            // find existing node
            auto node_it = val_map[key];
            node_it->keys.erase(key);   //remove from current bulk
            auto next_it = std::next(node_it, 1);
            if (next_it == value_key.end() ||
                 next_it->value != node_it->value + 1)
            {
                // no valid valued bulk, create one
                KvNode node;
                node.keys.insert(key);
                node.value = node_it->value + 1;
                val_map[key] = value_key.insert(next_it, node);
            }
            else
            {
                next_it->keys.insert(key);
                val_map[key] = next_it;
            }
            if (node_it->keys.empty() && node_it->value != 1)
            {
                // remove node_it
                value_key.erase(node_it);
            }
        }
    }
    /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
    void dec(string key) {
        auto it_val_map = val_map.find(key);
        if (it_val_map == val_map.end())
        {
            // key does not exist
            return;
        }
        else if (it_val_map->second->value == 1)
        {
            auto node_it = it_val_map->second;
            node_it->keys.erase(key);
            if (node_it->keys.empty() && node_it->value != 1)
            {
                value_key.erase(node_it);
            }
            val_map.erase(it_val_map);
        }
        else
        {
            auto node_it = it_val_map->second;
            auto prev_it = std::prev(node_it, 1);
            node_it->keys.erase(key);
            if (prev_it->value != node_it->value - 1)
            {
                // create one
                KvNode node;
                node.keys.insert(key);
                node.value = node_it->value - 1;
                val_map[key] = value_key.insert(node_it, node);
            }
            else
            {
                prev_it->keys.insert(key);
                val_map[key] = prev_it;
            }
            if (node_it->keys.empty() && node_it->value != 1)
            {
                value_key.erase(node_it);
            }
        }
    }
    /** Returns one of the keys with maximal value. */
    string getMaxKey() {
        auto it_max = std::prev(value_key.end(), 1);
        if (!it_max->keys.empty())
            return *(it_max->keys.begin());
        else
            return "";
    }
    /** Returns one of the keys with Minimal value. */
    string getMinKey() {
        auto it_min = value_key.begin();
        if (it_min->value == 1 && it_min->keys.empty())
            ++it_min;
        if (it_min != value_key.end() && !it_min->keys.empty())
            return *(it_min->keys.begin());
        else
            return "";
    }
};
/**
 * Your AllOne object will be instantiated and called as such:
 * AllOne obj = new AllOne();
 * obj.inc(key);
 * obj.dec(key);
 * string param_3 = obj.getMaxKey();
 * string param_4 = obj.getMinKey();
 */

 
 
 

Categories
木有技术

LeetCode 62. Unique Paths

原题:https://leetcode.com/problems/unique-paths/
robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?

Above is a 3 x 7 grid. How many possible unique paths are there?
Note: m and n will be at most 100.

思路

这是个经典的题目,反正就是动态规划的思路?说是动态规划,其实就是下一个状态怎么来的问题。此处的下一状态就是一个格子solution[m][n]他的结果是怎么来的问题,由于限定只能往右或者往下走,所以这个格子的走法无非是 从(m,n-1)和(m-1,n)走过来两种,只要把这两个状态的结果相加就是当前总的走法了。

解法

复杂度应该是O(m*n),做的时候在左侧和上侧加了个0边便于计算

public class Solution {
    public int uniquePaths(int m, int n) {
        int solutions[][] = new int[m+1][n+1];
        solutions[1][1]=1;
        for(int i=1; i<=m; i++){
            for(int j=1; j<=n; j++){
                if(i==1 && j==1)
                    continue;
                solutions[i][j] = solutions[i][j-1] + solutions[i-1][j];    // Comes from left, or upper side
            }
        }
        return solutions[m][n];
    }
}

 

Categories
木有技术

LeetCode 278. First Bad Version

做点简单的题目练练手,最近天天在写Scope脚本,都快忘记怎么写其他代码了。
吐槽一下垃圾长城宽带,上LeetCode都要自己开代理,不然根本加载不了

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.
You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

分析

这其实就是个变种的二分查找,只要注意找到一个bad version的时候,往前多看一个版本就能决定是否要继续二分下去了。

代码

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);
class Solution {
public:
    int firstBadVersion(int n) {
        int low = 1;
        int high = n;
        while(true){
            int mid = low + (high - low)/2;
            if(isBadVersion(mid)){
                //Look for previous cases
                bool isBad = isBadVersion(mid);
                if(isBad){
                    if(mid == 1)
                        return mid;
                    if(!isBadVersion(mid-1))
                        return mid;
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            } else {
                low = mid + 1;
            }
        }
    }
};

 

Categories
不学无术

LeetCode 322. Coin Change

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
Example 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)
Example 2:
coins = [2], amount = 3
return -1.
Note:
You may assume that you have an infinite number of each kind of coin.

思路

动态规划的问题,不过如果倒着做的话,似乎会超时…
所以考虑往前递推的情况,即当前要解决X元的找零问题的最佳解法且已知<X时的解法,手头有一堆面值为coins[i]的硬币的时候,对于每种可用的硬币我们要做的选择是:

  • 尝试使用coin[i],即当前的最优结果=(X-coins[i])元时的最优结果+1,这个1就是用了coins[i]这个硬币;
  • 保持现有结果不变

这两个方法当然是取最好的存下来了。

代码

class Solution {
public:
    int MAX_NUM = 65535;
    int coinChange(vector<int>& coins, int amount) {
        vector<int> solutions(amount+1, MAX_NUM); //0~amount,共amount+1个
        solutions[0] = 0;
        int coinSz = coins.size();
        for(int i=1; i<=amount; i++){
            for(int c=0; c<coinSz; c++){
                //得到当前的amount,要么就是用原有的结果,要么就是使用amount[i-coin] + 1个当前面值的
                if(coins[c] <= i){
                    solutions[i] = min(solutions[i], 1 + solutions[i-coins[c]]);
                }
            }
        }
        if(solutions[amount] == MAX_NUM)
            return -1;
        return solutions[amount];
    }
};

 

Categories
不学无术

LeetCode 217. Contains Duplicate

题目:https://leetcode.com/problems/contains-duplicate/
思路:弄个哈希表啊或者现成的用哈希(或者XX树)的容器就行了
代码:

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        set<int> numSet;
        int numSize = nums.size();
        for (int i = 0; i<numSize; i++) {
            if (numSet.count(nums[i]) == 0)
                numSet.insert(nums[i]);
            else
                return true;
        }
        return false;
    }
};