水水的动归

很容易想到DP 然后 f[i] = max(f[i-1],f[i-2] + num[i]);

class Solution {
public:
    int rob(vector<int> &num) {
        //f[i] = max(f[i-1],f[i-2]+num[i])
        if(num.size() <= 1) return num.empty() ? 0 : num[0];
        vector<int> f = {num[0],max(num[0],num[1])};
        for(int i = 2 ; i < num.size() ; i++)
        {
            f.push_back(max(f[i-1],f[i-2]+num[i]));
        }
        return f.back();
    }
};

一、管道

管道是进程间通信中最古老的方式,它包括 无名管道 和 有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。 无名管道由pipe()函数创建。

#include <stdio.h> 
#include <unistd.h>
 
#define INPUT 0
#define OUTPUT 1
 
int main()
{
    int files[2];
    pid_t pid;
    char buf[256];
    int returned_count;
    
    //创建无名管道
    pipe(files);
 
    //创建子进程
    
    if((pid = fork()) == -1) 
    { 
        perror("fork() error");
        return -1; 
    } 
 
    //执行子进程
    if(pid == 0)
    { 
        printf("in child process....\n");
 
        //子进程向父进程写数据,关闭管道的读端
        close(files[INPUT]);
        write(files[OUTPUT],"test data", strlen("test data"));
     
        exit(0);
    } 
    else
    { 
        //执行父进程
        printf("in the parent process...\n");
        //父进程从管道中读取子进程写的数据,关闭管道的写端
        close(files[OUTPUT]);
 
        returned_count = read(files[0], buf, sizeof(buf));
        buf[returned_count] = '\0';
        printf("%d bytes of data receiced from spawned process:%s\n", returned_count, buf);
    } 
    
    return 0;
}

二、消息队列

消息队列用于运行于同一台机器上的进程间通信,它和管道很相似,是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现。消息链表中节点的结构用msg声明。

事实上,它是一种正逐步被淘汰的通信方式,我们可以用流管道或者套接口的方式来取代它。所以,我们对此方法也不再解释,也建议读者忽略这种方式。

三、共享内存

共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销,但在现实中并不常用,因为它控制存取的将是实际的物理内存,在Linux系统下,这只有通过限制Linux系统存取的内存才可以做到,这当然不太实际。常用的方式是通过shmXXX函数族来实现利 用共享内存进行存储的。 使用共享内存时要掌握的唯一诀窍是多个进程之间对一定存储区d同步访问。若服务器进程正在将数据放入共享内存,则在它做完这一操作之前,客户进程不应当去读取这些数据。 通常,信号量是用来实现对共享内存访问的同步(记录锁也可以用于这种场合)。 使用共享存储来实现进程间通信的注意点是对数据存取的同步,必须确保当一个进程去读取数据时,它所想要的数据已经写好了。通常,信号量被要来实现对共享存 储数据存取的同步,另外,可以通过使用shmctl函数设置共享存储内存的某些标志位如SHM_LOCK、SHM_UNLOCK等来实现。

四、信号

信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。

五、信号量

信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:    (1) 测试控制该资源的信号量。    (2) 若此信号量的值为正,则允许进行使用该资源。进程将信号量减1。    (3)若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。    (4)当进程不再使用一个信号量控制的资源时,信号量值加1。如果此时有进程正在睡眠等待此信号量,则唤醒此进程。   维护信号量状态的是Linux内核操作系统而不是用户进程。我们可以从头文件/usr/src/linux/include /linux /sem.h 中看到内核用来维护信号量状态的各个结构的定义。信号量是一个数据集合,用户可以单独使用这一集合的每个元素。要调用的第一个函数是semget,用以获得一个信号量ID。

六、套接口

套接口(socket)编程是实现Linux系统和其他大多数操作系统中进程间通信的主要方式之一。我们熟悉的WWW服务、FTP服务等都是基于套接口编程来实现的。除了异地的计算机进程间外,套接口同样适用于本地同一台计算机内部的进程间通信。 关于这部分,可以参照《设计自己的网络蚂蚁》,链接为:。那里由常用的几个套接口函数的介绍和示例程序。这一部分或许是Linux进程 间通信编程中最须关注和最吸引人的一部分,毕竟,Internet 正在我们身边以不可思议的速度发展着,如果一个程序员在设计编写他下一个程序的时候,根本没有考虑到网络,考虑到Internet,那么,可以说,他的设计很难成功。

参考资料:

1.Linux下进程间通信

2.深刻理解Linux进程间通信(IPC)

一、管道

管道是进程间通信中最古老的方式,它包括 无名管道 和 有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。 无名管道由pipe()函数创建。

#include <stdio.h> 
#include <unistd.h>
 
#define INPUT 0
#define OUTPUT 1
 
int main()
{
    int files[2];
    pid_t pid;
    char buf[256];
    int returned_count;
    
    //创建无名管道
    pipe(files);
 
    //创建子进程
    
    if((pid = fork()) == -1) 
    { 
        perror("fork() error");
        return -1; 
    } 
 
    //执行子进程
    if(pid == 0)
    { 
        printf("in child process....\n");
 
        //子进程向父进程写数据,关闭管道的读端
        close(files[INPUT]);
        write(files[OUTPUT],"test data", strlen("test data"));
     
        exit(0);
    } 
    else
    { 
        //执行父进程
        printf("in the parent process...\n");
        //父进程从管道中读取子进程写的数据,关闭管道的写端
        close(files[OUTPUT]);
 
        returned_count = read(files[0], buf, sizeof(buf));
        buf[returned_count] = '\0';
        printf("%d bytes of data receiced from spawned process:%s\n", returned_count, buf);
    } 
    
    return 0;
}

二、消息队列

消息队列用于运行于同一台机器上的进程间通信,它和管道很相似,是一个在系统内核中用来保存消息的队列,它在系统内核中是以消息链表的形式出现。消息链表中节点的结构用msg声明。

事实上,它是一种正逐步被淘汰的通信方式,我们可以用流管道或者套接口的方式来取代它。所以,我们对此方法也不再解释,也建议读者忽略这种方式。

三、共享内存

共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销,但在现实中并不常用,因为它控制存取的将是实际的物理内存,在Linux系统下,这只有通过限制Linux系统存取的内存才可以做到,这当然不太实际。常用的方式是通过shmXXX函数族来实现利 用共享内存进行存储的。 使用共享内存时要掌握的唯一诀窍是多个进程之间对一定存储区d同步访问。若服务器进程正在将数据放入共享内存,则在它做完这一操作之前,客户进程不应当去读取这些数据。 通常,信号量是用来实现对共享内存访问的同步(记录锁也可以用于这种场合)。 使用共享存储来实现进程间通信的注意点是对数据存取的同步,必须确保当一个进程去读取数据时,它所想要的数据已经写好了。通常,信号量被要来实现对共享存 储数据存取的同步,另外,可以通过使用shmctl函数设置共享存储内存的某些标志位如SHM_LOCK、SHM_UNLOCK等来实现。

四、信号

信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。

五、信号量

信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:    (1) 测试控制该资源的信号量。    (2) 若此信号量的值为正,则允许进行使用该资源。进程将信号量减1。    (3)若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。    (4)当进程不再使用一个信号量控制的资源时,信号量值加1。如果此时有进程正在睡眠等待此信号量,则唤醒此进程。   维护信号量状态的是Linux内核操作系统而不是用户进程。我们可以从头文件/usr/src/linux/include /linux /sem.h 中看到内核用来维护信号量状态的各个结构的定义。信号量是一个数据集合,用户可以单独使用这一集合的每个元素。要调用的第一个函数是semget,用以获得一个信号量ID。

六、套接口

套接口(socket)编程是实现Linux系统和其他大多数操作系统中进程间通信的主要方式之一。我们熟悉的WWW服务、FTP服务等都是基于套接口编程来实现的。除了异地的计算机进程间外,套接口同样适用于本地同一台计算机内部的进程间通信。 关于这部分,可以参照《设计自己的网络蚂蚁》,链接为:。那里由常用的几个套接口函数的介绍和示例程序。这一部分或许是Linux进程 间通信编程中最须关注和最吸引人的一部分,毕竟,Internet 正在我们身边以不可思议的速度发展着,如果一个程序员在设计编写他下一个程序的时候,根本没有考虑到网络,考虑到Internet,那么,可以说,他的设计很难成功。

参考资料:

1.Linux下进程间通信

2.深刻理解Linux进程间通信(IPC)

分享一下预处理&&const&&sizeof里一些小技巧

define的用法

1.用define声明一月有多少秒

一开始很想这么写,感觉就是声明个常量。

#define SECONDS_JANUARY 2678400

而下面的写法就明显好的多。

#define SECONDS_JANUARY 60*60*24*31

这样的宏可以让计算表达式表现出程序员的意图和计算的方式。

2.用define声明标准的宏MIN

#define MIN(A,B) ((A)<=(B))?(A):(B)

这里其实主要就是考察一下三重条件操作符,记得一定要括括号,这最好变成习惯,不然会引发如下错误。

#define MUL(A,B) A*B
int main()
{
	int a = MUL(3+5,8) //希望的是(3+5)*8,最后得到3+5*8
}

const的用法

四个const区分

int b = 10;
const int *a = &b; //case 1
int const* a = &b; //case 2
int* const a = &b; //case 3
const int* const a = &b;//case 4

首先case 1 和 case 2是完全等价的。 如果const在星号左侧,const修饰的就是所指向的变量,如果const在星号右侧,修饰的就是指针本身。 所以如果是case1和case2的话,我们就不能修改指向的变量.

所以在case 1,case 2 下面的语句都是违法的.

*a = 600;//不能修改

但如果要修改指针a指向的值得,以下语句可以代替达到这种效果。

int b = 500;
const int* a = &b;
b = 30;//方法1 修改指向的内容
int c = 30;
a = &c; //方法2 指向新的内容

那如果是case3的话,也就是const在星号的右侧,说明指针本身是一个常亮。 那么就不能对指针本身做任何操作。例如以下的行为。

int b = 50 , c = 20;
int* const a;//错误 必须初始化,不然就永远指向未知。
int* const a = &b; //正确,初始化
*a = 500 ; //正确,可以修改
cout << a++ << endl ;//错误,不能对a做指针操作

而case 4也很明显就是既不能修改值,也不能修改指针。

为什么要用const成员函数呢?

因为一些成员函数是不需要改变类中的数据成员的,它们是只读函数。所以如果加上const标示可以提高程序的可读性,也可以防止这些函数企图修改数据成员的值,让编译器报错。

让我们来看看以下两个const函数写法:

int Point::GETY() const
{
	return yVAL;
}
//这个意思是const的成员函数,即函数不能修改数据成员。
const int Point::GETY()
{
	return yVAL;
}
//说明返回的值是一个const int.

那么问题来了,#define和const 都能修饰常量,哪种更好?

  • const常量有数据类型,而define没有,编译器可以对前者做类型检查,而后者只是字符替换,所以可能会在替换中产生未知的bug(边际效应)
  • 有些集成化的调试工具会调试const常量,却无法调试宏

2015的第一次出国旅行

匈牙利-布达佩斯

Smithsonian Image

Smithsonian Image

Smithsonian Image

Smithsonian Image

晚饭:HARD_ROCK RIB好吃,不过挺贵。
第二天去了链子桥,中饭吃了布达佩斯的快餐,味道奇怪的一B,晚饭去了比较有名的MENZA。

Smithsonian Image

Smithsonian Image

Smithsonian Image

Smithsonian Image

奥地利:第一顿晚饭吃了猪排,去看了茜茜公主。然后去了奥特莱斯购物了一天,吃了快餐鱼排味道不错。
当天晚上吃了越南餐厅,第三天去了美泉宫,美景宫。

Smithsonian Image

Smithsonian Image

Smithsonian Image 哈尔拾塔特:非常NICE的老板,在旅店吃了晚饭,第二天吃了个贵的要死的四星级,然后晚上吃了披萨。 景色非常美。

Smithsonian Image

Smithsonian Image

Smithsonian Image 克鲁姆洛夫,布拉格,红顶建筑风格。购物很便宜
吃了监狱餐厅和一家披萨店,布拉格吃了当地人很多的两个餐厅,便宜量大。