简单问题的特殊解法 LeetCode 215. 数组中的第K个最大元素

题目

链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

说明

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

代码模板

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {

    }
};

二分查找

解析

可以使用二分查找,查找目标是[left,right]之间第一个大于自身的其他元素个数小于k的数,这个数即为数组排序后的第 k 个最大的元素。
算法的时间复杂度为O(nlogn),和直接排序、最小堆的耗时差不多。
优点:

  • 空间复杂度O(1)
  • 不改变原数组

代码

class Solution
{
public:
    int findKthLargest(vector<int>& nums, int k)
    {
        auto minmax = minmax_element(nums.begin(), nums.end());
        int left = *minmax.first;
        int right = *minmax.second;

        int mid;
        int countGreat;
        while (left < right)
        {
            mid = left + (right - left) / 2;
            countGreat = count_if(nums.begin(), nums.end(), [mid](int n) { return n > mid; });
            if (countGreat >= k)
            {
                left = mid + 1;
            }
            else
            {
                right = mid;
            }
        }

        return left;
    }
};

LeetCode 297. 二叉树的序列化与反序列化

题目

链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

示例

你可以将以下二叉树:

    1
   / \
  2   3
     / \
    4   5

序列化为 "[1,2,3,null,null,4,5]"
提示: 这与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

说明

不要使用类的成员 / 全局 / 静态变量来存储状态,你的序列化和反序列化算法应该是无状态的。

代码模板

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {

    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {

    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

题解

思路

感觉最大的难点是分割字符串和删除多于的null。如果用C#、Java之类的,有强大的字符串操作函数,肯定写起来非常快。
无论是序列化还是反序列化,我们都可以使用层次遍历的方法。
反序列化中,我们先顺序生成所有节点,并放入一个数组。由于每个非空节点都有两个子节点(包括空节点),使用prevLevelTwiceIndex / 2记录当前节点的父节点索引。如果prevLevelTwiceIndex / 2对应的父节点为空,我们需要增加prevLevelTwiceIndex,直到prevLevelTwiceIndex / 2的值有效。

代码

class Codec 
{
public:
    string serialize(TreeNode* root) 
    {
        const string null = "null,";
        string mid;
        queue<TreeNode*> q;
        q.push(root);
        while (q.empty() == false)
        {
            auto node = q.front();
            q.pop();
            if (node == nullptr)
            {
                mid += null;
            }
            else
            {
                mid += to_string(node->val) + ",";
                q.push(node->left);
                q.push(node->right);
            }
        }

        int length = mid.length();
        while (length >= null.size())
        {
            bool failed = false;
            int midStart = length - null.size();
            for (int i = null.size() - 1; i >= 0; --i)
            {
                if (mid[midStart + i] != null[i])
                {
                    failed = true;
                    break;
                }
            }

            if (failed)
            {
                break;
            }

            length -= null.size();
        }

        if (length != mid.size())
        {
            mid = mid.substr(0, length);
        }

        if (mid.empty() == false)
        {
            mid = mid.substr(0, mid.size() - 1);
        }

        return "[" + mid + "]";
    }

    TreeNode* deserialize(string data) 
    {
        data = data.substr(1, data.size() - 2);
        vector<TreeNode*> nodes;

        string::size_type prev_pos = 0;
        string::size_type pos = 0;
        while ((pos = data.find(',', pos)) != string::npos)
        {
            string sub = data.substr(prev_pos, pos - prev_pos);
            ++pos;
            prev_pos = pos;
            if (sub == "null")
            {
                nodes.push_back(nullptr);
            }
            else
            {
                nodes.push_back(new TreeNode(stoi(sub)));
            }
        }

        string last = data.substr(prev_pos);
        if (last.empty() == false)
        {
            if (last == "null")
            {
                nodes.push_back(nullptr);
            }
            else
            {
                nodes.push_back(new TreeNode(stoi(last)));
            }
        }

        int prevLevelTwiceIndex = 0;
        for (int i = 1; i < nodes.size(); ++i)
        {
            while (nodes[prevLevelTwiceIndex / 2] == nullptr)
            {
                ++prevLevelTwiceIndex;
            }

            if (prevLevelTwiceIndex % 2 == 0)
            {
                nodes[prevLevelTwiceIndex / 2]->left = nodes[i];
            }
            else
            {
                nodes[prevLevelTwiceIndex / 2]->right = nodes[i];
            }

            ++prevLevelTwiceIndex;
        }

        return nodes.empty() ? nullptr : nodes.front();
    }
};

围炉网《WordPress 添加ICP备案号》一文中的错误修正

错误及修正

原文zh_CN.php代码第33行,把工信部的网址填错了。需要手动将http://www.miitbeian.gov.cn/修改为http://beian.miit.gov.cn/

个人感想

网上关于WordPress添加备案号的文章很多,往往一句define('WP_ZH_CN_ICP_NUM', true);就结束了,结果在docker版的WordPress里根本就不能显示备案号。
可能是WordPress在某次更新后删除了zh_CN.php文件。

围炉网原文

【声明】本文为AdamsLee原创,转载请注明出自围炉网并保留本文有效链接:WordPress 添加ICP备案号, 转载请保留本声明!

新装的wordpress 4.6.1 发现“设置”-“常规”并没有显示 “ICP备案号”的选项。在wp-config.php设置添加了define('WP_ZH_CN_ICP_NUM', true);后依然没有显示出来。
在网上搜寻了很久也没有发现有人有类似问题,只好自己研究比对,最后发现wp-content/languages下貌似少了zh_CN.php。添加zh_CN.php后,终于可以看到该选项了。zh_CN.php文件内容如下:

<?php
/**
 * ICP license number
 *
 * For compliance with the Telecommunications Regulations. Can be turned off
 * in wp-config.php.
 *
 * @since 3.7.0
 */
function zh_cn_l10n_settings_init() {
    if ( defined( 'WP_ZH_CN_ICP_NUM' ) && WP_ZH_CN_ICP_NUM ) {
        add_settings_field( 'zh_cn_l10n_icp_num',
            'ICP备案号',
            'zh_cn_l10n_icp_num_callback',
            'general' );
        register_setting( 'general', 'zh_cn_l10n_icp_num' );
    }
}

add_action( 'admin_init', 'zh_cn_l10n_settings_init' );

function zh_cn_l10n_icp_num_callback() {
    echo '<input name="zh_cn_l10n_icp_num" type="text" ' .
        'id="zh_cn_l10n_icp_num" value="' .
        esc_attr( get_option( 'zh_cn_l10n_icp_num' ) ) .
        '" class="regluar-text ltr" />' .
        '<p class="description">仅对WordPress自带主题有效。</p>';
}

function zh_cn_l10n_icp_num( $content ) {
    if ( defined( 'WP_ZH_CN_ICP_NUM' ) && WP_ZH_CN_ICP_NUM &&
            get_option( 'zh_cn_l10n_icp_num' ) ) {
        echo '<a href="http://www.miitbeian.gov.cn/" rel="nofollow" ' .
            'title="工业和信息化部ICP/IP地址/域名信息备案管理系统">' .
            esc_attr( get_option( 'zh_cn_l10n_icp_num' ) ) .
             "</a>\n";
    }
}

add_action( 'twentyten_credits', 'zh_cn_l10n_icp_num' );
add_action( 'twentyeleven_credits', 'zh_cn_l10n_icp_num' );
add_action( 'twentytwelve_credits', 'zh_cn_l10n_icp_num' );
add_action( 'twentythirteen_credits', 'zh_cn_l10n_icp_num' );
add_action( 'twentyfourteen_credits', 'zh_cn_l10n_icp_num' );
add_action( 'twentyfifteen_credits', 'zh_cn_l10n_icp_num' );
?>

docker下ElasticSearch的坑之重启物理机

重启物理机后,容器无法正常启动,提示:

max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

官方文档只有设置sysctl -w vm.max_map_count=262144,然而该设置在重启后会被重置,于是我们要将该设置固化:

echo "vm.max_map_count=262144" > /etc/sysctl.conf
sysctl -p

WordPress迁移中产生的一些问题

前几天,我更改了wordpress的ssl证书生成方式,于是噩梦开始了。
由于我的wordpress是用docker容器搭建的,结果重建容器后,wp-config.php文件也被重置了。看来挂载/var/www/html文件夹是非常必要的。

无限重定向

不知道为什么wordpress为什么不默认支持https,需要在wp-config.php头部添加:

$_SERVER['HTTPS'] = 'on';
define('FORCE_SSL_LOGIN', true);
define('FORCE_SSL_ADMIN', true);

这样就能正常进入网站了。

WP Statistics(统计)插件和评论显示IP错误

一般使用反向代理或CDN后,显示正确的评论IP只需要在wp-config.php头部添加:

if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  $list = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
  $_SERVER['REMOTE_ADDR'] = $list[0];
}

然而WP Statistics 12.6.3 中,这个设置并不奏效。我调试了一番后,发现插件获取IP用的既不是REMOTE_ADDR,也不是HTTP_X_REAL_IP,而是HTTP_X_FORWARDED_FOR的最后一个IP。真不知道作者是什么思路写下这种bug。
为了防止作者再写出别的bug,我直接伪造所有IP信息,把上面的代码修改为:

if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  $list = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
  $_SERVER['REMOTE_ADDR'] = $list[0];
  $_SERVER['HTTP_X_REAL_IP'] = $list[0];
  $_SERVER['HTTP_X_FORWARDED_FOR'] = $list[0];
}

丢失操作前的文章

谁叫你不勤备份啊!修改服务器前一定要备份。

写了一个1fichier的.net SDK

最近想用1fichier的网盘,顺手搞了一个.net SDK,项目地址 点我

1fichier优点如下:

  • 价格便宜
  • 可以使用FTP上传(不能用FTP下载)
  • 下载速度稳定,国内1~2MB/S
  • 可以同时上传100个文件
  • 没有容量限制
  • 可以上传单个最大100GB文件

1fichier限制如下:

  • 每秒最多只能发出3个API请求
  • 下载文件需要调用API获取临时下载地址(5分钟有效),每有一个文件就要调用一次
  • 只有付费用户才能调用除上传外的API
  • 普通用户下载要排队,一般要等几十分钟
  • 如果分享给其他用户直链(即hot link或CDN),需要消耗CDN流量点数,未付费用户和Access用户没有CDN流量,Premium用户每月有100GB的CDN流量。

总的来说,1fichier上传容易、下载麻烦,不适合备份照片、分享文件,只适合备份不需要经常下载的大文件。

C#全排列的泛型函数实现

C++、Python都有自带的库函数可以实现全排列的遍历,然而C#却没有。
我这里简单实现了一个泛型函数:

public static class Permutation
{
    /// <summary>
    /// 获取全排列,第一次调用前必须从小到大排序。
    /// </summary>
    /// <typeparam name="T">参数类型</typeparam>
    /// <param name="list">全排列数组</param>
    /// <returns>是否生成成功。</returns>
    public static bool NextPermutation<T>(IList<T> list)
        where T : IComparable<T>
        {
            int topIndex = -1;
            int length = list.Count;
            for (int i = length - 1; i > 0; --i)
            {
                if (list[i].CompareTo(list[i - 1]) > 0)
                {
                    topIndex = i;
                    break;
                }
            }

            if (topIndex < 0)
            {
                list.Reverse(0);
                return false;
            }

            int swapIndex = topIndex;
            for (int i = topIndex + 1; i < length; ++i)
            {
                if (list[topIndex - 1].CompareTo(list[i]) >= 0)
                {
                    break;
                }
                else
                {
                    swapIndex = i;
                }
            }

            list.Swap(swapIndex, topIndex - 1);
            list.Reverse(topIndex);
            return true;
        }

    public static void Swap<T>(this IList<T> list, int a, int b)
    {
        T temp = list[a];
        list[a] = list[b];
        list[b] = temp;
    }

    public static void Reverse<T>(this IList<T> list, int index)
    {
        int max = list.Count - 1;
        int length = (max - index) / 2;
        for (int i = 0; i <= length; ++i)
        {
            list.Swap(index + i, max - i);
        }
    }
}

使用时只需要排序后循环调用Permutation.NextPermutation即可。
此处使用的方法来自于Keosu全排列各种实现(非递归、递归),修复原文方法1的一个小bug后,用C#封装而成。