算法学习打卡日记

一来通过每日打卡的方式督促自己每天学习,二来总结一下知识点;主要面向自己,希望自己能坚持住吧,有一个好的结果

2019年1月18日打卡

  • 编程语言推荐C++(包含C)

  • 用scanf和printf相比cin/cout效率更高

  • int 的范围是±21亿,超过用long long 声明赋值后面加LL

  • 小数全用double

  • 小写字母比大写字母ASCII码大32

  • #define和const 都可以定义常量,推荐使用const

  • 定义无穷大的数 const int INF = 0x3fffffff

  • 形如 += ,/=的复合赋值可以加快编译速度

  • double输入时是%lf,输出时用%f即可,long long是%lld

  • scanf的%c是可以读入空格和换行的,因此sanf("%d%c",&a,&c);输入2 a后,字符变量c的值为输入的2后面的空格

  • 常用的输出格式 %md,m为可选数字:不足m位的整数右对齐m位,高位(左端)补空格,对高于m位的整数输出没有影响
    %0md:与上一种类似,只不过高位用0补齐而非空格,在某些题目要求中特别有用
    %.mf:使浮点数保留m位小数,保留规则为四舍六入五成双(5后面有数,进一;5后面没有数,通过进0或1使5前一位变成偶数)

  • 通过getchar和putchar输入输出单个字符,getchar能读入空格

  • typedef 可以给数据类型重命名,比如: typedef long long LL (在宏定义的位置)

  • 常用math函数,math.h 或 cmath fabs(double x)–绝对值,floor(double x)/ceil()–向下取整/向上取整,二者返回值均为double,pow(double a,double b)–a的b次方,注意输入a,b均为double类型,sqrt(double x)–算术平方根,log–自然对数e为底的对数,如果求任意底的需要用换底公式,sin,cos,tan–输入必须是double的弧度制(角度/180 * Π),round(double x)–四舍五入,返回值是double类型,输出时需要(int)强制转型

  • if中如果是x!=0,可以省略后面改为if(x);如果表达式是x==0,换成!x

2019年01月19日打卡

今天做了几道oj练习,也算充当任务量了,内容太简单了就不po了

  • if判断中的小技巧在while循环中同样适用
  • do-while后面有分号别忽略
  • C语言不允许for循环中初始化,C++可以,所以默认语言选为CPP也是前文提到的
  • int数组全赋值为0只用一个大括号即可:int a[] = {}
  • 如果数组大小超过十的六次方,要在main函数之外声明(申请),这样把变量从栈转移到静态区,否则会内存不够异常退出
  • 给数组所有元素赋值函数memset(数组名,值,sizeof(数组名)),头文件为string.h,建议只用来赋值0或-1,否则由于补码问题可能会出错(后面会介绍更实用的)
  • 用gets(str)获取字符串时如果前面是int要先用getchar()吃掉int后面默认的回车
  • 字符串由于以\0结尾,开辟空间时要多+1
  • 如果不是使用scanf的%s或者gets(str)函数接受字符串输入,末尾要记得手动加\0
  • string.h头文件strlen(str)函数,strcmp(str1,str2) 1比于2 小负等零大正;strcpy(str1,str2) 2给1 ;strcat(str1,str2) 2接到1末尾;
  • string.h中的利器:sscanf和sprintf

sscanf(str,"%d",&n)————将str转化为数字赋值给整型变量n

sprintf(str,"%d",n)————将整数n转化为字符串str

其中格式化的部分(第二个参数)还可以根据str格式匹配适应,比如:

#include<stdio.h>
#include<string.h>
int main(){
   
    char s[20] = "123:3.14,sdffg";
    char str[10];
    int a;
    double b;
    sscanf(s, "%d:%lf,%s", &a, &b, str);
    printf("%d,%f,%s",a,b,str);
}

这段代码就是根据字符串s中的格式匹配拆分成三个部分

当然逆过来的sprintf也成立

另外sscanf还支持正则表达式

  • 一维数组做参数不用写明长度,二维数组做参数要写明第二维长度

2019年01月20日打卡

  • 结构体不能定义自己,但是可以定义自身类型的指针变量
  • 结构体的指针类型用->代替(*p).
  • cin.getline(str,100)读入一整行赋值给字符数组str[100]
  • getline(cin,str)读入一行赋值给字符串类型str
  • 浮点数比较相等,定义

const double eps = 1e-8

#define Equ(a,b) ((fabs((a)-(b)))<(eps))————比较相等

#define More(a,b) (((a)-(b))>(eps))————a大于b:即a>b+eps

#define Less(a,b) (((a)-(b))<(-eps))————a小于b:即a<b-eps

#define MoreEqu(a,b) (((a)-(b))>(-eps))————a大于等于b:即a>b-eps

#define LessEqu(a,b) (((a)-(b))<(eps))————a小于等于b:即a<b+eps

2019年01月21日打卡

  • 圆周率π const double PI = acos(-1.0);(记得引入math.h)
  • 对于多点测试要循环读入数据可以采用while(scanf("%d",&n) != EOF) {}来循环,因为scanf的返回值代表成功读入的参数的个数,如果读取失败返回-1,用EOF(end of file)表示,而对于gets可以判断返回值是否为空:while(gets(str) != NULL)
  • PAT B1001
/*
 * Callatz(3n+1)猜想
 */
#include <stdio.h>
int main(){
   
    int count = 0;
    int n;
    scanf("%d",&n);
    while(n != 1){
   
        if(n %2==1) {
   
            n = 3*n+1;
        }
            n /= 2;
        count +=1;
    }
    printf("%d",count);
}

/*
 * PAT B1032
 */
#include <stdio.h>
const int MAX = 100001;
int score[MAX] = {
   0};
int main(){
   

    int n;
    scanf("%d",&n);
    int num,sco;
    for (int i = 0;i<n;++i){
   
        scanf("%d%d",&num,&sco);
        score[num] += sco;
    }
    num = 1;
    sco = 0;
    for (int i = 1; i < n +1; ++i) {
   
        //printf("%d",score[i]);
        if (score[i] > sco){
   
            sco = score[i];
            num = i;
        }
    }
    printf("%d %d",num,sco);
}

/*
 * PAT B1036
 */
#include <stdio.h>
int main(){
   
    int n;
    char c;
    scanf("%d %c", &n, &c);
    int col;
    if (n % 2 == 0) {
   
        col = n/2;
    } else {
   
        col = n / 2 + 1;
    }
    for (int i = 0; i < col; ++i) {
   
        if (i == 0 || i == col - 1) {
   
            for (int j = 0; j < n; ++j) {
   
                printf("%c",c);
            }
        } else {
   
            for (int j = 0; j < n; ++j) {
   
                if (j == 0 || j == n - 1) {
   
                    printf("%c",c);
                } else {
   
                    printf(" ");
                }
            }
        }
        printf("\n");
    }
}
  • 日期差值:拆分成年月日,一直加一,超过就进位,加到比第大日期大一天位置:
//
// Created by zhaopeng on 19-1-21.
//

/*
 * codeup1928 日期之差
 */
#include <stdio.h>

int month[13][2] = {
   {
   0, 0}, {
   31, 31}, {
   28, 29}, {
   31, 31}, {
   30, 30}, {
   31, 31}, {
   30, 30}, {
   31, 31}, {
   31, 31},
                         {
   30, 30}, {
   31, 31}, {
   30, 30}, {
   31, 31}};

bool isLeap(int year) {
   
    return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main(){
   

    int time1, time2, y1, y2, m1, m2, d1, d2;
    while (scanf("%d%d", &time1, &time2) != EOF) {
   
        if (time1 > time2) {
   
            int temp = time1;
            time1 = time2;
            time2 = temp;
        }
        y1 = time1 / 10000;
        y2 = time2 / 10000;
        m1 = time1 % 10000 /100;
        m2 = time2 % 10000 /100;
        d1 = time1 % 100;
        d2 = time2 % 100;

        int ans = 1;
        while ((y1 < y2) || (m1 < m2) || (d1 < d2)) {
   
            d1++;
            if (d1 == month[m1][isLeap(y1)]+1) {
   
                m1 ++;
                d1 = 1;
            }
            if (m1 == 13) {
   
                y1 ++;
                m1 = 1;
            }
            ans ++;

        }
        printf("%d\n", ans);
    }
    return 0;


}
/*
 * PAT B1009 说反话,将给定的句子中的单词反序
 */
#include <stdio.h>
int main(){
   
    char str[90][90];
    int num = 0;
    while (scanf("%s", str[num]) != EOF) {
   
        num++;
    }
    for (int i = num - 1; i > -1; --i) {
   
        printf("%s", str[i]);
        if (i != 0) {
   
            printf(" ");
        }
    }


}

2019年01月22日打卡

  • C语言的qsort函数由于涉及很多指针操作并且没有规避快排中的最简单情况,所以推荐使用C++中的sort函数

sort(首元素地址,尾元素地址的下一地址,比较函数)

  • 使用时引入#include 以及 using namespace std
  • 简单数据类型比较函数的定义:
bool cmp(T a,T b){
   
    return a>b;
}
//其中T可以为int,char,double
sort(a,a+n+1,cmp);
  • 对于结构体同理可以根据结构体内的元素写比较函数
bool cmp(struct s1,struct s2){
   
    return s1.val>s2.val;
}
//按照结构体的val属性从大到小排列
  • 二级排序
bool cmp(struct s1,struct s2){
   
    if(s1.a != s2.a)
        return s1.a > s2.a;
    else
        return s1.b > s2.b;
}
//
  • 容器排序:STL 标准容器只有vector,string,deque可以使用sort排序,排序的cmp函数与容器元素类型有关,比如
bool cmp(int a,int b){
   
    return a > b;
}
vector<int> vi;
sort(vi.begin(),vi.end,cmp);
  • string的话不写cmp直接按照字典顺序排序
string str[3] = {
   "bbb","sss","aaaaa"};
sort(str,str+3);
//或者指定cmp
bool cmp(string s1,string s2){
   
    return s1.length() < s2.length();
}
sort(str,str+3,cmp);    //按照长度从小到大排序

散列

将元素通过函数转化成一个整数,使得这个整数可以唯一地表示这个元素

  • 线性变换
  • 除留余数法: H(key) = key % m; m为素数
  • 平方取中法: 将key平方之后取中间的几位

防止冲突的方法:

  • 线性探查法: 一直+1寻找没有被占据的位置
  • 平方探查法: +/- k++的平方
  • 链地址法: 每个哈西值对应一个单链表

空间换取时间例题:在m个预查询的数中判断n个数是否出现过,m,n均小于十的五次方————空间换时间
开辟十的五次方个bool数组,在m输入时就将出现的位置置为true

/*
 * m,n < 1 e5
 * 判断n个数中是否出现在m中
 * 空间换时间
 */
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
bool maxN[10010] = {
   false};
int main(){
   
    int n, m;
    int num;
    vector<int> Nv;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; ++i) {
   
        scanf("%d", &num);
        maxN[num] = true;
    }
    for (int j = 0; j < n; ++j) {
   
        scanf("%d", &num);
        if (maxN[num]) {
   
            Nv.push_back(num);
        }
    }
    for (int k = 0; k < Nv.size() - 1; ++k) {
   
        printf("%d ", Nv.at(k));
    }
    printf("%d", Nv.at(Nv.size()-1));
}
  • 字符串散列:将字符串转化为惟一的数
    常用的方法时进制转换:
    比如如果只有大写字母或者小写字母,那就把26进制转化为十进制,对应的数值肯定是惟一的
int hashFun(char s[], int len){
   
    int id = 0;
    for(int i = 0;i < len;++i){
   
        id = id * 26 + (s[i]-'A');
    }
    return id;
}

如果是多种字母混合,可以扩充进制位数,比如大小写混合就是26+26=52位,其中大写对应从0-25,小写对应从26-51

int hashFun(char s[], int len){
   
    int id = 0;
    for(int i = 0;i < len;++i){
   
        if(s[i] >= 'A' && s[i] <= 'Z' ){
   
            id = id * 52 + (s[i] - 'A');
        }else if(s[i] >= 'a' && s[i] <= 'z'){
   
            id = id * 52 +(s[i] - 'a') + 26;
        }


    }
    return id;
}
/*
 * 给出N个字符串(由恰好三位大写字母组成),再给除M个查询字符串,问每个查询字符串出现的次数
 */
#include <stdio.h>

const int maxn = 100;
char S[maxn][5], temp[5];
int hashTable[26 * 26 * 26 + 10];
int hashFun(char s[], int len){
   
    int id = 0;
    for(int i = 0;i < len;++i){
   
        id = id * 26 + (s[i]-'A');
    }
    return id;
}
int main(){
   
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i) {
   
        scanf("%s", S[i]);
        int id = hashFun(S[i], 3);
        hashTable[id]++;
    }
    for (int j = 0; j < m; ++j) {
   
        scanf("%s", temp);
        int id = hashFun(temp, 3);
        printf("%d\n", hashTable[id]);
    }
    return 0;
}

2019年01月23日打卡

分治法:

注意分治法解决的子问题应该是互相独立,没有交叉的,如果子问题之间存在相交部分不应该用分治法

  • 使用递归的方法实现分治法较为容易

要理解递归,你要先理解递归,直到你能理解递归

按字典序的全排列问题

/*
 * 全排列,以n=3为例,体会分治递归思想
 */
#include <stdio.h>
const int MAX = 11;
int n, p[MAX], hashTable[MAX] = {
   false};

void generateP(int index) {
   
    if (index == n + 1) {
   
        for (int i = 1; i <= n; ++i) {
   
            printf("%d", p[i]);
        }
        printf("\n");
        return;
    }
    for (int j = 1; j <= n; ++j) {
   
        if (hashTable[j] == 0) {
   
            p[index] = j;
            hashTable[j] = true;
            generateP(index + 1);
            hashTable[j] = false;
        }
    }
}
int main() {
   
    n = 3;
    generateP(1);
    return 0;
}

n皇后问题

/*
 * n皇后问题
 */
#include <stdio.h>
#include <math.h>
const int MAX = 10000;
int n, p[MAX], hashTable[MAX] = {
   false};
int count = 0;
void generateP(int index) {
   
    if (index == n + 1) {
      //  递归边界,生成一个合法方案
        count++;    //能到达这里的一定是合法方案
        return;
    }

    for (int i = 1; i <= n; ++i) {
     //第i行
        if (hashTable[i] == 0) {
       //第i行还没有皇后
            bool flag = true;   //flag为true表示当前皇后不会和其他皇后冲突
            for (int pre = 1; pre < index; ++pre) {
    //遍历之前的皇后
                //第index列的皇后行号为i,第pre列的皇后行号为p[pre]
                if (abs(index - pre) == abs(i - p[pre])) {
   
                    flag = false;   //在一条对角线
                    break;
                }


            }
            if (flag) {
    //可以把皇后放在第i行

                p[index] = i;   //另index列的皇后行号为i
                hashTable[i] = true;    //第i行已经被占用
                generateP(index + 1);
                hashTable[i] = false;
            }

        }
    }
}
int main() {
   
    n = 8;
    generateP(1);
    printf("%d", count);
    return 0;
}

贪心

  • 总是考虑当前局部最优,以达到全局最优
/*
 * PAT B 1020 月饼
 */
#include <stdio.h>
#include <algorithm>

using namespace std;
const int MAX = 1001;
struct MOON {
   
    double store;
    double sell;
    double price;
};

bool cmp(MOON m1, MOON m2) {
   
    return m1.price > m2.price;
}
int main(){
   
    int n;
    double total;
    scanf("%d%lf", &n, &total);
    MOON moon[MAX];
    for (int i = 0; i < n; ++i) {
   
        scanf("%lf", &moon[i].store);
    }
    for (int j = 0; j < n; ++j) {
   
        scanf("%lf", &moon[j].sell);

    }
    for (int k = 0; k < n; ++k) {
   
        moon[k].price = moon[k].sell / moon[k].store;
    }

    double value = 0.0;
    sort(moon, moon + n, cmp);
    for (int l = 0; (l < n)&&(total > 0); ++l) {
   
        if (total <= moon[l].store) {
   
            value +=  moon[l].price * total;
            total = 0;
        } else {
   
            value += moon[l].sell;
            total -= moon[l].store;
        }
    }
    printf("%.2f", value);
}

组个最小数


/*
 * PAT B 1023
 * 组个最小数
 */
#include <stdio.h>
int main() {
   
    int count[10];
    for (int i = 0; i < 10; ++i) {
   
        scanf("%d", &count[i]);

    }

    for (int j = 1; j < 10; ++j) {
   
        if (count[j] != 0) {
   
            printf("%d", j);
            --count[j];
            break;
        }
    }
    for (int k = 0; k < 10; ++k) {
   
        while (count[k] != 0) {
   
            printf("%d", k);
            --count[k];
        }
    }
}

区间贪心

区间选点问题
给出N个闭区间[x,y],求最少需要确定多少个点,才能使每个闭区间中都至少存在一个点

#include <stdio.h>
#include <algorithm>

using namespace std;
const int MAX = 110;
struct AREA {
   
    int x, y;

} area[MAX];

bool cmp(AREA a1, AREA a2) {
       //左端点从大到小排序,左端点相同,右端点从小到大排序
    if (a1.x != a2.x) {
   
        return a1.x > a2.x;
    } else {
   
        return a1.y < a2.y;
    }
}
int main() {
   
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
   
        scanf("%d%d", &area[i].x, &area[i].y);

    }
    sort(area, area + n, cmp);
    int ans = 1, lastX = area[0].x;     //ans记录不相交区间个数,lastX记录上一个被选中的区间左端点
    for (int j = 1; j < n; ++j) {
   
        if (area[j].y < lastX) {
   
            lastX = area[j].x;
            ++ans;
        }
    }
    printf("%d", ans);
}

二分

  • 二分法查找
int binarySearch(int A[], int left, int right, int x) {
   
    int mid;
    while (left < right) {
   
        mid = (left + right) / 2;       //防溢出替换为mid = left + (right - left) / 2
        if (A[mid] == x) {
   
            return mid;
        } else if (A[mid] > x) {
   
            right = mid - 1;
        } else {
   
            left = mid + 1;

        }


    }
    return -1;
}
</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值