LintCode 解题记录 17.5.31(tag:Array)


最近由于毕业答辩,碰巧撞上端午假期,所以一直没有静下心来做题。今天终于清闲下来了,于是刷一刷题。
第一题 LintCode 132 Pattern
没做出来。上网看了别人的思路,用stack保存最大的数,用third保存次大的数,然后从后往前遍历。
代码:

    bool find132pattern(vector<int>& nums) {
         stack<int> s;
         int third = INT_MIN, len = nums.size();
         for (int i = len-1; i >= 0; i--) {
             if (nums[i] < third) return true;//如果当前元素值小于third,说明找到了132Pattern,它们是nums[i], s.top(), third。
             while (!s.empty() && s.top() < nums[i]) { //如果当前元素大于栈顶元素,则循环出栈更新third直到栈顶元素小于当前元素。
                 third = s.top();
                 s.pop();
             }
             s.push(nums[i]);//将当前元素入栈
         }
         return false;
    }

至于为什么能想到这种做法,不是很清楚。该方法可以保证third值小于s.top()值且third值在s.top()值后面。

第二题 3Sum Closest
KSum系列题目的变型题。本质上和3Sum没什么区别,先排序然后用Two Pointers法。
时间复杂度为O(nlogn)+O(n^2)=O(n^2),空间复杂度为O(1)。(因为只用了几个变量)

    int threeSumClosest(vector<int> nums, int target) {
        int left, right, ret, sum, closest;
        left = right = ret = sum = 0, closest = INT_MAX;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            left = i+1; right = nums.size()-1;
            while (left < right) {
                sum = nums[i] + nums[left] + nums[right];
                if (sum < target) left++;
                if (sum > target) right--;
                if (abs(sum - target) < closest) {
                    closest = abs(sum - target);
                    ret = sum;
                }
                if (closest == 0) break;
            }
        }
        return ret;
    }

第三题 Best Time to Buy and Sell Stock
题目概括的来说就是给定一个数组,寻找max (aj-ai) s.t. 0 <= i <= j < n
思路:顺序遍历,如果当前价格小于变量buy,那么更新buy继续遍历。否则说明此时应该以buy买入,然后再往后遍历,找到最大的卖价,更新profit。时间复杂度是O(n)。

    int maxProfit(vector<int> &prices) {
        int ret = 0, buy = INT_MAX, sell = 0;
        for (int i = 0; i < prices.size();) {
            if (prices[i] < buy) {
                buy = prices[i++];
                continue;
            }
            while (i < prices.size()-1 && prices[i] < prices[i+1]) i++;
            ret = max(ret, prices[i] - buy);
            i++;
        }
        return ret;
    }

在网上看到了一种思路更好的解法,比如我在第i天买入,能获得的最大利润就是在i ~ n天内的最高价卖出。这里采用后序遍历。

    int maxProfit(vector<int> &prices) {
        int maxprice = 0, ret = 0;
        if (prices.size() == 0) return 0;
        for (int i = prices.size()-1; i >= 0; i--) {
            maxprice = max(maxprice, prices[i]); //用maxprice来记录第i天到第n天的最高卖价。
            ret = max(ret, maxprice - prices[i]);
        }
        return ret;
    }

第四题 Best Time to Buy and Sell Stock II
上一题的变型,即可以进行多次交易。那么为了获得最大利润,就需要尽可能多的交易。也就是说如果明天的价格比今天的高,那么我就可以今天买入,明天卖出。然后明天同理。
先贴一个自己写的矬代码:

    int maxProfit(vector<int> &prices) {
        int buy_price = INT_MAX, sell_price = INT_MIN, ret = 0;
        int i = 0;
        bool buy = true;
        while (i < prices.size()) {
            if (prices[i] <= buy_price && buy) {
                buy_price = prices[i];
            }
            else if (prices[i] > buy_price && buy) {
                sell_price = prices[i];
                buy = !buy;
            }
            else if (prices[i] > sell_price && !buy) {
                sell_price = prices[i];
            }
            else if (prices[i] < sell_price && !buy) {
                ret += sell_price - buy_price;
                buy_price = prices[i];
                buy = !buy;
            }
            i++;
            if (i == prices.size() && !buy) {
                ret += sell_price - buy_price;
            }
        }
        return ret;
    }

再贴一个别人写的代码:

    int maxProfit(vector<int> &prices) {
        int ret = 0;
        for (int i = 1; i < prices.size(); i++) {
            if (prices[i] > prices[i-1]) {
                ret += prices[i] - prices[i-1];
            }
        }
        return ret;
    }

总结:没有对比就没有伤害:-(

第五题 Best Time to Buy and Sell Stock III
上两题的变型,这里只能做两次交易。我的想法就是:先做第一次交易,然后在第一次交易的基础上寻找第二次交易。时间复杂度为O(n^2),不过也AC了。
代码:

    int find(vector<int> &prices, int start) {
        int ret = 0, buy = INT_MAX;
        for (int i = start; i < prices.size(); i++) {
            if (prices[i] <= buy) {
                buy = prices[i];
                continue;
            }
            ret = max(ret, prices[i] - buy);
        }
        return ret;
    }
    int maxProfit(vector<int> &prices) {
        int ret = 0, buy = INT_MAX, sell = 0, temp = 0;
        for (int i = 0; i < prices.size(); ) {
            if (prices[i] <= buy) {
                buy = prices[i++];
                continue;
            }
            while (i < prices.size()-1 && prices[i] < prices[i+1]) {
                i++;
            }
            int temp = prices[i] - buy + find(prices, i+1);
            ret = max(ret, temp);
            i++;
        }
        return ret;
    }

官方思路:
最简单的方法就是对每一个时间点,将其所有两边的数组都执行一次Best Time to Buy and Sell Stock的解法,但这会带来O(n^2)的时间复杂度。实际上当计算prices[0]到prices[i]的收益时,我们已经计算过prices[0]到prices[i-1]的最大收益了,prices[0]到prices[i]的最大收益应该是当前卖出能获得的最大收益和prices[0]到prices[i-1]的最大收益中,较大的那一个。那么就可以以i点为分割,左半段最大收益的数组left,右半段最大的收益right,我们就可以遍历一遍这两个数组,找出最大的left+right组合。时间复杂度为O(n),空间复杂度也为O(n)。

    int maxProfit(vector<int> &prices) {
        int len = prices.size();
        if (len == 0) return 0;
        vector<int> left(len, 0);
        vector<int> right(len, 0);
        int leftmin = prices[0], rightmax = prices[len-1];
        for (int i = 1; i < len; i++) {
            leftmin = min(leftmin, prices[i]);
            left[i] = max(left[i-1], prices[i] - leftmin);
        }
        for (int i = len-2; i >= 0; i--) {
            rightmax = max(rightmax, prices[i]);
            right[i] = max(right[i-1], rightmax - prices[i]);
        }
        int ret = INT_MIN;
        for (int i = 0; i < len; i++) {
            ret = max(ret, left[i]+right[i]);
        }
        return ret;
    }

第二种方法就是动态规划。我们维护两种量,一个是当前到达第i天时最大可以进行j次交易,最好的利润是多少(global[i][j]),另一个是当到达第i天时,最多可进行j次交易,且最后一次交易在当天卖出的最好利润是多少(local[i][j]),那么递推公式如下:
global[i][j] = max(global[i-1][j], local[i][j])
local[i][j] = max(global[i-1][j-1]+max(0,diff), local[i-1][j]+diff)
理解一下:
递推公式1:
第i天时最大可进行j次交易所获得的最好利润就是:1.第i天没有交易,那么就是global[i-1][j] 2.第i天进行了交易,那么就是local[i][j]。global[i][j] 取两者中的较大值。
递推公式2:
同样可以分为两种情况:1.第i天的交易导致的最好利润,就是global[i-1][j-1]+max(0, diff) 2.如果假设不是第i天的交易导致的最好利润,那么就是local[i-1][j]+diff。也就是说原本在第i-1天卖出的现在移到第i天卖出,那么所获得的最好利润就需要加上差价diff。
代码:

class Solution {
public:
    int maxProfit(vector<int> &prices) {
        if (prices.empty()) return 0;
        int n = prices.size(), g[n][3] = {0}, l[n][3] = {0};
        for (int i = 1; i < prices.size(); ++i) {
            int diff = prices[i] - prices[i - 1];
            for (int j = 1; j <= 2; ++j) {
                l[i][j] = max(g[i - 1][j - 1] + max(diff, 0), l[i - 1][j] + diff);
                g[i][j] = max(l[i][j], g[i - 1][j]);
            }
        }
        return g[n - 1][2];
    }
};

类似于背包问题中空间复杂度的优化方法,这里也可以采用一维数组来代替二维数组。由于覆盖的先后顺序关系,需要采用倒序遍历,这样可以取到正确的g[j-1]的值,而非被覆盖后的值。

class Solution {
public:
    int maxProfit(vector<int> &prices) {
        if (prices.empty()) return 0;
        int g[3] = {0};
        int l[3] = {0};
        for (int i = 0; i < prices.size() - 1; ++i) {
            int diff = prices[i + 1] - prices[i];
            for (int j = 2; j >= 1; --j) {
                l[j] = max(g[j - 1] + max(diff, 0), l[j] + diff);
                g[j] = max(l[j], g[j]);
            }
        }
        return g[2];
    }
};

这道动态规划的题目还是不是很熟练,多练练吧。贴两个此题的参考链接:
http://www.cnblogs.com/grandyang/p/4281975.html
http://blog.csdn.net/linhuanmars/article/details/23236995

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java代码实现: ```java import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class PointInArea { public static void main(String[] args) { List<Point> polygon = new ArrayList<>(); polygon.add(new Point(119.019, 32.263)); polygon.add(new Point(119.019, 32.013)); polygon.add(new Point(118.765, 32.013)); polygon.add(new Point(118.765, 32.263)); boolean isP1InArea = isPointInPolygon(new Point(119.037089, 32.259867), polygon); boolean isP2InArea = isPointInPolygon(new Point(118.821489, 32.077388), polygon); boolean isP3InArea = isPointInPolygon(new Point(118.80657099, 32.0353893), polygon); boolean isP4InArea = isPointInPolygon(new Point(118.894173, 32.077862), polygon); System.out.println("P1 is in area: " + isP1InArea); System.out.println("P2 is in area: " + isP2InArea); System.out.println("P3 is in area: " + isP3InArea); System.out.println("P4 is in area: " + isP4InArea); } private static boolean isPointInPolygon(Point point, List<Point> polygon) { int n = polygon.size(); boolean isInside = false; for (int i = 0, j = n - 1; i < n; j = i++) { if (((polygon.get(i).lat <= point.lat && point.lat < polygon.get(j).lat) || (polygon.get(j).lat <= point.lat && point.lat < polygon.get(i).lat)) && (point.lng < (polygon.get(j).lng - polygon.get(i).lng) * (point.lat - polygon.get(i).lat) / (polygon.get(j).lat - polygon.get(i).lat) + polygon.get(i).lng)) { isInside = !isInside; } } return isInside; } private static class Point { double lng; double lat; public Point(double lng, double lat) { this.lng = lng; this.lat = lat; } } } ``` 思路: 1. 将框起来的范围的经纬度读入程序中,存储为一个多边形的顶点列表。 2. 对于每个要判断的点,使用射线法判断其是否在多边形内部。具体来说,从该点向右发射一条射线,计算该射线与多边形的交点数量,如果是奇数,则该点在多边形内部,否则在外部。 需要注意的是,使用射线法的前提是多边形的顶点按照顺时针或逆时针顺序排列,否则算法不正确。 代码规范和编码能力方面,我尽量遵守了Java编码规范,使用了合适的变量名和注释,代码逻辑清晰易懂。 中间数据和代码执行结果如下: ```text P1 is in area: true P2 is in area: false P3 is in area: false P4 is in area: true ``` 中间数据就是框起来的范围的经纬度,不再赘述。代码执行结果表明,P1和P4在多边形内部,而P2和P3在外部。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值