C++模板元编程 习题: add_const_ref
要学的东西还有很多啊…
习题2-0. 编写一个一元元函数add_const_ref<T>,如果T是一个引用类型,就返回T,否则返回T const&.
#include "add_const_ref.h" int main() { int a = 5; add_const_ref<int>::type c = a; add_const_ref<int&>::type d = a; return 0; }
#ifndef ADD_CONST_REF #define ADD_CONST_REF template <class T> struct add_const_ref; template<class T> struct add_const_ref { typedef T const& type; }; template<class T> struct add_const_ref<T&> { typedef T type; }; #endif
终于写完毕业论文了!
其实是终于交了送外审了,从11月到现在,感觉过了几个世纪。
不过一想研究生阶段也快结束了,有种莫名的不舍…
App推荐——TaoMix2 干活、睡觉专用辅助声音
之前MUJI Sleep给我的印象很深,也是用来辅助睡眠的。今天发现一个进阶版的,这个App也是用来播放一些自然声响的,但它的特点是可以混音:里面有个白色的点,播放的时候会在几种音源之间游走。比如,可以在水声、鸟叫声、树叶声中间各种游动,应该是掺杂比例的不同。
不知为何,想起了高斯混合模型…
Android: https://play.google.com/store/apps/details?id=air.com.demute.TaoMix&hl=zh_CN
iOS: (TaoMix与TaoMix2)
https://itunes.apple.com/cn/app/taomix-create-your-own-relaxing/id660104097?mt=8
https://itunes.apple.com/cn/app/taomix-2-yong-zi-ran-sheng/id1032493819?mt=8
Windows 下使用MinGW编译Cython
用Visual C++编译器也是可以的(找不到vcvarsall.bat可以看这篇),不过为了后面移植方便,目前的项目还是用MinGW.
步骤其实很简单,参考http://cython.readthedocs.io/en/latest/src/tutorial/appendix.html。
稍微翻译一下就是:
- 从这里http://www.mingw.org/wiki/HOWTO_Install_the_MinGW_GCC_Compiler_Suite 下载个MinGW Installer. 下载、安装的时候记住是32位版本的,因为64位版仍旧有些不兼容现象。
- 运行安装下载的程序。Cython只需要最基本的包(basic package)就行了,主要是为了里面的C++编译器
- 将你安装MinGW的目录设置到PATH环境变量中。默认位置应该是C:\MinGW\bin
- 在Python安装目录下创建配置文件。如果Python是安装在C:\Python27目录下,那就创建C:\Python27\Lib\distutils\distutils.cfg,然后文件内容为
[build] compiler = mingw32
这样就可以使用GCC编译啦~
本文是对文章Basics of Convex Analysis的部分翻译,若本文对您的任何权益造成侵犯,请联系我。
This article is a partial translation of Basics of Convex Analysis, if this infringes any of your rights, please contact me.
次梯度以及一阶最优性条件
若下述不等式成立:
[latex]f(z) \geqslant{f(x)} + <z-x, y>, \forall z \in X.[/latex]
则我们说[latex]y\in X[/latex]是函数[latex]f \in \Gamma _0(X)[/latex]在[latex]x \in X[/latex]点上的一个次梯度,并且属于[latex]f[/latex]在该点(用[latex]\partial f(x)[/latex]表示)的一个次微分。
上述不等式表明函数[latex]f[/latex]的图像(graph)是由不等式右侧定义的超平面所(hyperplane)支撑的。一个次梯度因此也是这众多支持超平面其中一个的“斜率(slope)”。如果该函数在点[latex]x[/latex]处可微,则这样的次梯度有且仅有一个(即标准梯度),与此对应地,也只有一个支持超平面。相对地,如果一个函数在点[latex]x[/latex]处不可谓(比如,在[latex]x[/latex]处有个扭曲)那么就能有无穷多个支持超平面,并且相对应地,在该点的次微分是一个连续的次梯度的集合。
一个典型的例子是绝对值函数[latex]f(x)=|x|[/latex],它在0点是不可导的。但在这个点上,它可以由[latex]l(x)=\alpha x, \alpha \in [-1,1][/latex]组成的所有直线支持。这个集合即该函数在0点的次微分,用[latex]\partial f(0)[/latex]表示。
函数[latex]f(x)=|x|[/latex]的演示(粗线表示)以及其中两个支持直线(虚线表示)。这两条支持直线都有次微分[latex]\partial f(0)[/latex]中的斜率。注意,那条水平线也是支持超平面之一,表明[latex]0 \in \partial f(0)[/latex]。并且因此由一阶条件(下文定义),这个函数在原点有一个极小值。
现在,通过定义非限制问题中的一个最优点[latex]x^{\#}[/latex],必有[latex]f(z) \geqslant{f(x^{\#}) + <z-x, 0>}, \forall z \in x [/latex],并且因此0必须是函数[latex]f[/latex]在[latex]x^{\#}[/latex]点处的一个子梯度。
这就是一阶最优性条件(FOC):
[latex]x^{\#} \in arg min_{x}{f(x)} \Longleftrightarrow 0 \in \partial f(x^{\#})[/latex]
如果我们将次微分看做一个运算符那么,直观地,寻找极小可以看做“逆转”次微分并计算它在点0的值的过程,即[latex]x^{\#}=(\partial f)^{-1} (0)[/latex]。我们稍后再进一步介绍,但这个逆转次微分运算符的思路是非常重要的。
在继续之前,有必要提一下(并且这并不难理解)下述包含关系对于次微分的和是成立的:
[latex]\sum_{i}{\partial f_i} \subseteq \partial \sum_{i}{f_i} [/latex]
对关注的大部分问题而言,上述关系可以强化为相等的关系, 但注意如果[latex]0 \in \sum_{i}{\partial f_i (x^\dagger)}[/latex],则上述包含关系意味着[latex]0 \in \partial \sum_{i}{f_i (x^\dagger)}[/latex],这对于证明[latex]x^\dagger[/latex]是个极小值而言(这正是我们最感兴趣之处)足矣。
浙江电信一到晚上就连不上原来的日本服务器,白天稳定在150ms偶尔还丢个包。纠结了一阵子后,决定换到香港的服务器。
LeetCode 47. Permutations II
用回溯法完成,跟普通排列问题不同的是,需要排除掉一些重复“路径”。
可以这样做,先把输入数组排个序,这样重复的数就在相邻位置了。随后在回溯探求的过程中,我们要保证相同值的两个数nums[i], nums[j],如果i<j,那遍历只能有一种次序:nums[i]先,nums[j]后。
换句话说,就是判断这种情况是需要提前终止的:两个数nums[i]==nums[j] && i<j,但是nums[i]还没有被遍历。所以找个东西记录一下访问就行了。
时间复杂度是O(N!),空间复杂度是O(N)
class Solution { public: void permSub(vector<int>& nums, vector<int>& sub, vector<vector<int>>& results, vector<bool>& used){ if(sub.size() == nums.size()){ results.push_back(sub); return; } else { for(int i=0; i<nums.size(); i++){ if(used[i]) continue; if(i>0 && nums[i]==nums[i-1] && !used[i-1]) continue; sub.push_back(nums[i]); used[i] = true; permSub(nums, sub, results, used); sub.pop_back(); used[i] = false; } } } vector<vector<int>> permuteUnique(vector<int>& nums) { sort(nums.begin(), nums.end()); vector<vector<int>> results; vector<bool> used(nums.size(), false); vector<int> sub; permSub(nums, sub, results, used); return results; } };
LeetCode 368. Largest Divisible Subset
思路:
想到一个词叫“传递性”,在这边应该也适用。就是如果b%a==0,然后c%b==0,那么肯定有c%a==0. 按照这个方法来构造一个集合就可以了,应该是动态规划的思想,results[i]保存包含数组元素nums[i]的最佳集合,构建集合的时候,首先从之前的results[j] (j=0…i-1)里面找到能够“传递”过来的集合(nums[i]%nums[i]==0)选作最佳(相当于找到c%b==0,当然这里的b是之前results[j]里面的最大元素,即nums[j])然后加上本身的nums[i]就构成了到第i个元素为止的最佳集合,如此继续…
时间复杂度应该是O(n^2)
class Solution { public: vector<int> largestDivisibleSubset(vector<int>& nums) { if(nums.empty()) return nums; sort(nums.begin(), nums.end()); int bestIndex = 0; vector<vector<int>> results(nums.size()); for(int i=0; i<nums.size(); i++){ for(int j=0; j<i; j++){ //nums[j] < nums[i] if(nums[i]%nums[j]==0 && results[i].size() < results[j].size()) results[i] = results[j]; } results[i].push_back(nums[i]); if(results[bestIndex].size() < results[i].size()) bestIndex = i; } return results[bestIndex]; } };
思路很重要。
给定一个长度n的字符串s和限制k,将s中的部分字符替换(替换次数<=k)后,能得到连续字符(如AAAA)的长度最大为多少?
使用滑动窗口的思路可以在O(n)时间复杂度的情况下解决这个问题。需要记录当前窗口内各个字符的计数值(可以看做分布情况)以及当前窗口的起始点,窗口内最多字符的计数best。我们知道,最多字符的计数best+修改数量k如果还是不能使得当前窗口内的字符都统一的话,就得把窗口缩小(起始点后挪)。窗口缩小时记得把窗口计数更新一下。
这里有一个tricky的地方,best值本来在滑动窗口的时候是要更新的,因为可能窗口过了这个best会变小。但是由于我们要找的只是个最优的值,所以这个情况并不需要考虑对best进行更新,反正它也成不了最优。
代码
class Solution { public: int characterReplacement(string s, int k) { //sliding window solution int charCount[26] = {0}; int w_start = 0, best = 0; for(int w_end = 0; w_end < s.size(); w_end++){ charCount[s[w_end]-'A']++; best = max(best, charCount[s[w_end]-'A']); if(best+k <= w_end-w_start){ //replace k chars in current window, // if we still can't have the optimal // we will shrink the left border of window charCount[s[w_start]-'A']--; w_start++; } } return s.size()-w_start; } };