先正序计算每个位置左max
倒序计算每个位置右max
当前水位 = min(左max,右max)- 当前高度
蓄水量为各个位置蓄水量求和
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int trap(int* height, int heightSize){
int out=0,max=0;
int *tl=(int*)malloc(sizeof(int)*heightSize);
memset(tl,0,heightSize);
for(int i=1;i<heightSize;i++){
max=max<height[i-1]?height[i-1]:max;
tl[i]=max;
}
max=0;
for(int i=heightSize-2;i>0;i--){
max=max<height[i+1]?height[i+1]:max;
int t=max<tl[i]?max:tl[i];
t=t-height[i];
if(t>0){
out+=t;
}
}
return out;
}
如果喜欢栈顶的甜点的学生存在,那么不管他们在队伍的哪个位置,必定会遍历到他。否则,一定无法继续拿掉栈顶甜点。
int countStudents(int* students, int studentsSize, int* sandwiches, int sandwichesSize){
int arr[2];
memset(arr, 0, sizeof(arr));
for (int i=0; i<studentsSize; ++i) {
++arr[students[i]];
}
for (int i=0; i<sandwichesSize; ++i) {
if (arr[sandwiches[i]] == 0) break;
--arr[sandwiches[i]];
}
return arr[0] + arr[1];
}
先使用快慢指针找中点
反转后半部分链表
交叉合并两个链表
void reorderList(struct ListNode* head){
struct ListNode *tmp = head;
int ListLen = 1;
while (tmp->next != NULL) {
ListLen++;
tmp = tmp->next;
}
struct ListNode **ListArry = malloc(sizeof(struct ListNode*) * ListLen);
tmp = head;
int i = 0;
while (tmp->next != NULL) {
ListArry[i] = tmp;
i++;
tmp = tmp->next;
}
ListArry[i] = tmp;
tmp = head;
struct ListNode *tmp2 = NULL;
for (int i = 0; i < ListLen / 2; i++) {
tmp2 = tmp->next;
tmp->next = ListArry[ListLen - 1 - i];
tmp = tmp->next;
tmp->next = tmp2;
tmp = tmp->next;
}
tmp->next = NULL;
}
typedef struct minstack{
int val;
int size;
struct minstack *next;
struct minstack *top;
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() {
MinStack *root = (MinStack *)malloc(sizeof(MinStack));
root->next = NULL;
root->size = 0;
root->top = NULL;
return root;
}
void minStackPush(MinStack* obj, int x) {//入栈
MinStack *node = minStackCreate();
node->val = x;
node->next = obj->top;
obj->top = node;
obj->size++;
}
void minStackPop(MinStack* obj) {//出栈
if(obj->size == 0) return;
MinStack *cur = obj->top;
obj->top = obj->top->next;
obj->size--;
free(cur);
}
int minStackTop(MinStack* obj) {//获取栈顶的值
if(obj->size == 0) return 0;
return obj->top->val;
}
int minStackGetMin(MinStack* obj) {
MinStack *cur = obj;
MinStack *top = obj->top;
if(cur->size == 0) return 0;
int minret = cur->top->val;
int size = cur->size;
while(size--)
{
int temp = cur->top->val;
minret = minret < temp ? minret : temp;
cur->top = cur->top->next;
}
cur->top = top;
return minret;
}
void minStackFree(MinStack* obj) {
if(obj->size == 0)
{
return;
}
while(obj->size > 0)
{
MinStack *temp = obj->top;
obj->top = obj->top->next;
free(temp);
obj->size--;
}
}
用两个栈实现队列的入队、出队
一个栈只进行入栈,相当于入队
另一个栈只进行出栈,相当于出队
typedef struct {
int top1; //栈1的栈顶指针
int top2; //栈2的栈顶指针
int size; //栈的大小
int count; //队列中的元素个数
int *S1; //栈1
int *S2; //栈2
} MyQueue;
/** Initialize your data structure here. */
//初始化两个栈
MyQueue* myQueueCreate() {
MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));
queue->top1 = -1;
queue->top2 = -1;
queue->size = 100;
queue->count = 0; //队列中当前元素个数0
queue->S1 = (int*)malloc(queue->size * sizeof(int));
queue->S2 = (int*)malloc(queue->size * sizeof(int));
return queue;
}
void myQueuePush(MyQueue* obj, int x) {
if(obj->top1 == -1)
{
while(obj->top2 != -1)
{
obj->S1[++obj->top1] = obj->S2[obj->top2--]; //将栈2中的所有元素保存到栈1
}
}
obj->S1[++obj->top1] = x; //新元素入栈相当于入队
obj->count++; //队列元素个数加一
}
int myQueuePop(MyQueue* obj) {
if(obj->top2 == -1)
{
while(obj->top1 != -1)
{
obj->S2[++obj->top2] = obj->S1[obj->top1--]; //将栈1中的元素保存到栈2中
}
}
obj->count--;
return obj->S2[obj->top2--];
}
/*查看队头元素,即查看栈2的栈顶元素*/
int myQueuePeek(MyQueue* obj) {
if(obj->top2 == -1)
{
while(obj->top1 != -1)
{
obj->S2[++obj->top2] = obj->S1[obj->top1--];
}
}
return obj->S2[obj->top2];
}
/*队列为空返回true,否则返回false */
bool myQueueEmpty(MyQueue* obj) {
if(obj->count == 0)
return true;
else
return false;
}
void myQueueFree(MyQueue* obj) {
free(obj->S1);
free(obj->S2);
free(obj);
}
SVM
想要的就是找到各类样本点到超平面的距离最远,也就是找到最大间隔超平面。任意超平面可以用下面这个线性方程来描述:
w(T)*x+b=0
二维空间点 (x,y) 到直线 Ax+By+C=0 的距离公式是:
扩展到 n 维空间后,点 x=(x1,x2…xn) 到直线 wTx+b=0 的距离为:
假设有一个超平面H:ωTx+b=0能正确地将样本划分开来,那么同时也肯定存在两个平行于H的平面H1和H2:
H1:ωTx+b=1
H2:ωTx+b=1
距离超平面 H距离最近的正负样本正好就分别在H1和 H2上,而这样的样本就是 支持向量。
对于任意样本 (xi,yi)有,若 yi=1,即为正样本,满足 ωTxi+b>0;若 yi=−1,即为负样本,满足 ω(T)xi+b<0。
令:
使用之前推出的任意点 xx到超平面的距离的公式,不难发现,超平面H1H1和 H2H2之间的距离是:
这个东西就叫做 间隔。
而SVM的目标是就是找到一个超平面,使得 间隔取到最大值,同时也要能保证正确地划分正负样本。
超平面由法向量w和截距b决定,法向量指向的一侧为正类,另一侧为负类
函数间隔
在超平面wx+b=0确定的情况下,|wx+b|能够相对地表示点x距离超平面的远近。wx+b的符号与类标记y的符号是否一致能够表示分类是否正确。所以可用变量y(wx+b)来表示分类的正确性及确信度-统计学习方法(李航)
函数间隔可以表示分类预测的正确性及准确度,但是选择分类超平面时,只有函数间隔还不够,因为只要成比例地改变w和b,,比如说2w和2b,超平面并没有改变,但是函数间隔却称为原来的2倍
几何间隔
统计学习方法
最大间隔分类器Maximum Margin Classifier的定义
对一个数据点进行分类,当超平面离数据点的“间隔”越大,分类的确信度(confidence)也越大。所以,为了使得分类的确信度尽量高,需要让所选择的超平面能够最大化这个“间隔”值。这个间隔就是下图中的Gap的一半。
很喜欢统计学习方法中关于最大间隔的描述:
不仅将正负实例点分开,而且对最难分的实例点(离超平面最近的点)也有足够大的确信度将它们分开,这样的超平面应该对未知的新实例有很好的分类预测能力-统计学习方法
统计学习方法中关于最大间隔法
虚线上的点便叫做支持向量Support Vector,在线性可分情况下,训练数据集的样本点中与分离超平面最近的样本点的实例
满足公式:y(wx+b)-1=0
在决定分离超平面时只有支持向量起作用
统计学习方法Page:115定义
深入SVM
学习的对偶算法
应用拉格郎日对偶性,通过求解对偶问题(dual problem)得到原始问题(primal problem)的最优解,这就是线性可分支持向量机的对偶算法(dual algorithm),优点为对偶问题更容易求解,引入核函数,进而推广到非线性分类问题
求解步骤
将拉格郎日函数L(w,b,a)分别对w,b求偏导数并令其等于0
将以上的结果代入之前的L