leetcode题解日练--2016.7.4

编程日记,尽量保证每天至少3道leetcode题,仅此记录学习的一些题目答案与思路,尽量用多种思路来分析解决问题,不足之处还望指出。标红题为之后还需要再看的题目。

今日题目:1、买卖股票II;2、topK元素;3、统计未重复数字个数;4、整数分解的最大乘积。

122. Best Time to Buy and Sell Stock II | Difficulty: Medium

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 as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
题意:一天可以进行多次股票买卖,如何才能在一个给定股票走势的数组中找到最佳买卖方案。
思路:直接贪心,只要后面一天的价格比前一天的高,则进行一次买卖操作。
代码:
C++

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

结果:8ms

347. Top K Frequent Elements | Difficulty: Medium

Given a non-empty array of integers, return the k most frequent elements.

For example,
Given [1,1,1,2,2,3] and k = 2, return [1,2].

Note:
You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.

题意:从一个数组中找到出现的频率前k高的数。
思路:
1、topK问题,首先可以将所有的数据用一个哈希表来存储。然后考虑使用桶排序,将创建一个大小为nums.size()+1的桶,这个桶的key是数组中元素出现的次数,value就是元素本身。那么通排序好了之后直接从后往前遍历就可以了。
C++

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int,int> map;
        vector<int> res;
        for(int i=0;i<nums.size();i++)
            map[nums[i]]++;
        vector<vector<int>> bucket(nums.size()+1);
        for(auto num:map)
            bucket[num.second].push_back(num.first);
       for (int i = bucket.size() - 1; i >= 0 && res.size() < k; --i) {
            for (int num : bucket[i]) {
                res.push_back(num);
                if (res.size() == k)
                    break;
            }
        }
        return res;
    }
};

结果:44ms

2、前面的哈希表的过程一样,区别在于之后用的筛选出最大的k个数的方法。方法1使用的通排序,方法2使用优先队列数据结构。因为一共有n个数,取k个数出来。那么前n-k次入队操作不加入到结果中,最后k次入队才加入结果。
这里需要注意的地方是优先队列要将map的second,也就是数字出现次数而不是数字出现的值放在前面。 pq.push(make_pair(it.second,it.first));
C++

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int,int> map;
        vector<int> res;
        for(int i=0;i<nums.size();i++)
            map[nums[i]]++;
        priority_queue <pair<int,int>> pq;
        for(auto it : map)
        {
            pq.push(make_pair(it.second,it.first));
            if(pq.size()>map.size()-k)
            {
                res.push_back(pq.top().second);
                pq.pop();
            }
        }
        return res;
    }
};

结果:40ms

357. Count Numbers with Unique Digits | Difficulty: Medium

Given a non-negative integer n, count all numbers with unique digits, x, where 0 ≤ x < 10^n.

Example:
Given n = 2, return 91. (The answer should be the total numbers in the range of 0 ≤ x < 100, excluding [11,22,33,44,55,66,77,88,99])
题意:找到10^n次方内有多少个不带重复位的数字。11,22,33这些属于重复位的数字。
思路:
当不知道规律的时候,尝试去模拟一下。首先,数字一共有0,1,2,3,4,5,6,7,8,9这10种。当n>=11的时候,数字个数将不会再增加。这个很好理解,11位数无论怎么选都必定至少有2个数字是重复的。那么只要考虑n为0-10的情况。
n=0时,很显然一共有1个数符合条件。
n=1时,把数据分成两部分来看,n=0时已经包含的和n=1新增的。这两部分个数分别为1和9。
n=2时,还是一样去看数据,n=1时已经包含的和新增的。这两部分分别是10和81。81怎么来得呢?对于所有的两位数,每次选择了第一位之后,第二位都还有9种选择可能,而第一位一共也是9中选择的可能,所以共有81种组合。
n=3时,这两部分是91和648。648又是怎么来的呢?首先三位数是在两位数的基础上又补了一位,从另一个角度看,原本有90个两位数,加了一位之后相当于第三位有10种取法,共900种取法。原本的两位数中,有81个无重复数和9个重复数。这9个重复数增加的数字必定也是重复数,所以新增的非重复数只能在原来的81个中产生。这81个中前两位各不重复,当增加第三个位的时候,一共只要8种取法,所以新增非重复数是81*8 = 648.
好像找到规律了,对于n,用数组A[n]来表示第n位新加的可能性。
A[0] = 1;A[1] = 9;A[2] = 9*9 = 81;A[3]=9*9*8=648;A[4]=9*9*8*7……
S[n] = A[0] * A[1] * A[2] *……A[n]
代码:
C++

class Solution {
public:
    int countNumbersWithUniqueDigits(int n) {
        int res=0;
        int A[n+1];
        if(n==0||n==1)    return pow(10,n);
        if(n>10)    n=10;
        A[0] = 1;
        A[1] = 9;
        for(int i=2;i<=n;i++)
        {

             A[i] = A[i-1]*(11-i); 

        }
        for(int i=0;i<=n;i++)
            res+=A[i];
        return res;
    }
};

结果:0ms

343. Integer Break | Difficulty: Medium

Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get.

For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4).

Note: You may assume that n is not less than 2 and not larger than 58.
题意:给一个整数n,返回能相加等于n的数的乘积最大值。
思路:
不妨先观察下规律
n=2 —–1*1=1
n=3——2*1=2
n=4——2*2=4
n=5——2*3=6
n=6——3*3=9
n=7——3*4=12
n=8——3*3*2=18
n=9——3*3*3=27
n=10——3*3*4=36
n=11——5+6——2*3*3*3=54
n=12——6+6——3*3*3*3=81
好像找到了一些规律,尽可能多拼凑3,如果剩下的是4,就换成2个2.
代码:

class Solution {
public:
    int integerBreak(int n) {
    int res=1;
    if(n==2||n==3)  return n-1;
    while(n>4)
    {
        res*=3;
        n-=3;
    }
    res*=n;
    return res;
    }
};

结果:0ms

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值