2019年7月

前 K 个高频元素

问题描述

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:
输入: nums = [1], k = 1
输出: [1]

说明:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/top-k-frequent-elements

思路

首先,在元素与元素出现次数之间建立一个map映射;
然后申请一个pair<int,int>类型的vector,并将这些映射关系存入到vector中。
将vector中元素按照second(元素出现次数)从大到小排序。
最后,将前k个pair元素的first(元素值)存入到一个vector即可。

题解

class Solution {
public:
    static bool cmp(const std::pair<int, int> &left, const std::pair<int, int> &right) {
        return left.second > right.second;
    }
    vector<int> topKFrequent(vector<int> &nums, int k) {
        std::map<int, int> count;
        for(int i=0;i<nums.size();i++) count[nums[i]]++;
        vector<pair<int, int>> buf;
        for(auto each:count) buf.push_back(each);
        sort(buf.begin(), buf.end(), cmp);
        vector<int> ans;
        for (auto each:buf) {
            if (ans.size() < k) {
                ans.push_back(each.first);
            }
        }
        return ans;
    }
};

小菜鸡对map的理解

map是key-value的对应关系。

平时用的话,假如k-v都是int型,那么map<int,int> tmp即可。
map是自动有序的,是根据key递增的顺序进行排序的。

内部实现的简单化理解

可以把map想象成两部分:
第一部分-pair<int,int> buf这一部分是key-value;
第二部分-搜索二叉树,节点为pair类型。

假设现在有<3,4>,<4,10>,<7,6>,<6,4>,<4,2>
最开始搜索树是空的,建立根节点<3,4>;
下一个<4,10>的key=4>3,所以<4,10>为根节点<3,4>的右子树;
同理,<7,6>为<4,10>的右子树;
而6<7,所以<6,4>为<7,6>的左子树。
4出现在<4,10>的节点上,所以用2替换10;

FullSizeRender1.jpg

四数之和

问题描述

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:
答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum

思路

和三数之和的思路是一样的,只不过又加了一层循环。
三数之和 https://www.irene.ink/archives/5/

题解

class Solution {
public:
    vector<vector<int>> ret;

    vector<vector<int>> fourSum(vector<int> &nums, int target) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        if (n < 4) return ret;
        for (int i = 0; i < n - 3; i++) {
            if (i != 0 && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < n - 2; j++) {
                if (j != i + 1 && nums[j] == nums[j - 1]) continue;
                int left = j + 1;
                int right = n - 1;
                while (left < right) {
                    if (nums[i] + nums[j] + nums[left] + nums[right] < target) {
                        left++;
                    } else if (nums[i] + nums[j] + nums[left] + nums[right] > target) {
                        right--;
                    } else{
                        ret.push_back({nums[i],nums[j],nums[left],nums[right]});
                        left++;
                        while (left<right&&nums[left]==nums[left-1]) {
                            left++;
                        }
                    }
                }
            }
        }
        return ret;
    }
};

反转链表 II

问题描述

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii

思路

思路比较简单。
将反转前的链表存在一个vector tmp1中,按照题目要求对tmp1进行反转。
根据反转后的tmp1建立一个新链表。

题解

class Solution {
public:
    ListNode *reverseBetween(ListNode *head, int m, int n) {
        int len = 0;
        if (head == nullptr) return nullptr;
        ListNode *p = head;
        vector<int> tmp1;
        ListNode *head1;
        while (p != nullptr) {
            len++;
            tmp1.push_back(p->val);
            p = p->next;
        }
        vector<int> tmp2(tmp1);
        int count = 0;
        for (int i = m-1; i <= n-1; i++) {
            tmp1[i] = tmp2[n-1 - count];
            count++;
        }
        ListNode *tmp= nullptr;
        for (int i = 0; i < len; i++) {
            if (tmp == nullptr) {
                tmp = new ListNode(tmp1[i]);
                head1 = tmp;
            } else {
                tmp->next = new ListNode(tmp1[i]);
                tmp = tmp->next;
            }
        }
        return head1;
    }
};

整数转罗马数字

问题描述

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

示例 1:
输入: 3
输出: "III"

示例 2:
输入: 4
输出: "IV"

示例 3:
输入: 9
输出: "IX"

示例 4:
输入: 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.

示例 5:
输入: 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/integer-to-roman

思路

思路很简单,就是从最高位开始抽离每一位进行计算。

题解

class Solution {
public:
   string intToRoman(int num) {
        string ret;
        if (num > 3999 || num < 1) return ret;
        else {
            int tmp1=num/1000;
            int tmp11= num % 1000;
            int tmp2=tmp11/100;
            int tmp21=tmp11%100;
            int tmp3= tmp21/10;
            int tmp31=tmp21%10;
            for(int i=0;i<tmp1;i++){
                ret+="M";
            }
            if(tmp2==4){
                ret+="CD";
            } else if(tmp2==9){
                ret+="CM";
            } else if(tmp2<5){
                for(int i=0;i<tmp2;i++){
                    ret+="C";
                }
            } else if(5<=tmp2){
                ret+="D";
                for(int i=0;i<tmp2-5;i++){
                    {
                        ret+="C";
                    }
                }
            }
            if(tmp3==4){
                ret+="XL";
            } else if(tmp3==9){
                ret+="XC";
            } else if(tmp3<5){
                for(int i=0;i<tmp3;i++){
                    ret+="X";
                }
            } else if(5<=tmp3){
                ret+="L";
                for(int i=0;i<tmp3-5;i++){
                    {
                        ret+="X";
                    }
                }
            }
            if(tmp31==4){
                ret+="IV";
            } else if(tmp31==9){
                ret+="IX";
            } else if(tmp31<5){
                for(int i=0;i<tmp31;i++){
                    ret+="I";
                }
            } else if(5<=tmp31){
                ret+="V";
                for(int i=0;i<tmp31-5;i++){
                    {
                        ret+="I";
                    }
                }
            }

        }
        return ret;
    }
};