目录

算法

编写一个复制输入到输出的程序,并将其中连连续的多个空格用一个空格代替

  • 思维逻辑:

    1. 多个空格用一个空格代替 可以 被理解为只保留一串空格里的第一个空格

    2. 使用 getchar() 依次读取输入的每一个字符直到结尾, 考虑哪些字符被保留?答案是: 它不是空格 或者 它是一串空格里的第一个空格

    3. 那么如何判断一串空格里第一个空格? 答案 是判断该空格前一个字符是否为空格, 所以我们需要一个变量存储上一个读取的字符

#include <stdio.h>
#define NONBLANK 'a'
int main( int argc, char *argv[] )
{
    int c;      // 当前字符
    int last_c; // 上一个字符

    last_c = NONBLANK;
    while( ( c = getchar() ) != EOF )
    {
        if( c != ' ' || last_c != ' ' )
            putchar( c );
        last_c = c;
    }
    return 0;
}

编写程序统计输入的单词个数,这里单词单纯定义为连续输入的字符,中间不包含空白字符

  • 思维逻辑

    1. 还是从getchar()依次读取输入的每一个字符直到结尾入手,我们考虑下字符的状态,只有两种 : 在单词中不在单词中

    2. 我们对在单词中的字符进行计数, 考虑下计数规则 : 我们对多字符单词hello和单字符单词a都只计数一次

    3. 那么我们如何实现这种计数?我们的计数循环是每次读入一个字符,那么这个字符跟单词必须是一对一的关系,即: 单词中只能有这么一个字符,每次读到这个字符时,单词数+1,读取到单词内其他字符时不加

    4. 那么单词中有这种字符么?答案是: 首字符 或者是 尾字符, 任意单词只有一个 首字符尾字符

    5. 如何判断首字符: 首字符的前一个字符是空白字符 或者 是输入程序读入的第一个字符,实现上,我们需要一个变量last_c存储前一个字符,在程序开始时可以设置last_c为空格,来兼容程序读入的第一个字符是单词首字符的情况

    6. 如何判断尾字符: 尾字符的后一个字符是空白字符 或者 尾字符后面是EOF,用一个字符存储后一个字符???这个逻辑比较变扭,不采用

    7. 综上,对单词计数的逻辑是: 该字符在单词内 并且 是首字符

#include <stdio.h>
#define BLANK ' '
int main( int argc, char *argv[] )
{
    int c;      // 当前字符
    int last_c; // 上一个字符
    int count;

    last_c = BLANK;
    count = 0;

    while( ( c = getchar() ) != EOF )
    {
        if( c != ' ' && c != '\t' && c != '\n' && ( last_c == ' ' || last_c == '\t' || last_c == '\n' ) )
            count ++;
        last_c = c;
    }
    printf("count : %d\n",count);
    return 0;
}

根据数组打印一个竖直的直方图

  • 思维逻辑

    1. 竖直的概念的理解 : 行数应该是数组中最大的那个数 max = 10

    2. 从上到下打印,第一层循环次数是最终要打印的行数,每一行里面,对这个数组每一项进行遍历

    3. 以下标为arr[0]为例,它在第一层循环下,输出应该是 8 个空格,然后是 2 个 *, arr[0]的值为 2, 8 个空格可以理解为 max - 2, 每次打印了一个空格, 都应该将 max - 2 的值减去 1,当max - 2随着循环被减为 0 时,再进行循环就打印 * 号了

    4. 如果 i 为当前打印的行数,max - 2 - i 就是剩余需要打印的空格数, 如果该值大于 0的话,那么打印空格,否则打印 *

    5. 综上,算法的逻辑就是,求出最大行数max和数组长度len, 外层循环max次,当前次为i,里循环len,当前项为j,判断打印 空格*的逻辑是 max - arr[j] - i > 0

#include <stdio.h>
int main( int argc, char *argv[] )
{
    int arr[] = { 2, 5, 1, 4, 9, 1, 3, 8, 10, 2, 4, 9};
    int max = 0;
    int len = sizeof(arr) / sizeof(int);
    for ( int i = 0; i < len; i++ )
    {
        if( arr[i] > max )
            max = arr[i];
    }
    for( int i = 0; i < max; i++ )
    {
        for( int j = 0; j < len; j++ )
        {
            if( max - arr[j] - i > 0 )
                printf(" ");
            else
                printf("*");
        }
        printf("\n");
    }
    return 0;
}
// 打印效果:
//         *   
//     *   *  *
//     *  **  *
//     *  **  *
//     *  **  *
//  *  *  **  *
//  * **  ** **
//  * ** *** **
// ** ** ******
// ************

素数 / 质数

  • 只能被 1 和 自身整除的数

八皇后问题

  • 8 x 8 的国际象棋上放置八个皇后,任意两个皇后都不能处于同一横行,纵行,斜线上。下图是一种解法,总共有92种解法。

- - - x - - - -
- - - - - - x -
- - x - - - - -
- - - - - - - x
- x - - - - - -
- - - - x - - -
x - - - - - - -
- - - - - x - -

数独问题

  • 9 x 9 的大九宫格中有9个 3 x 3 的小九宫格。默认在其中填写一些数字,在其他空格处填入1到9的数字,使得每个数字在每个小九宫格内只出现一次,并且在大九宫格中,每横行,纵行只出现一次。比如下面这个数组就有51965种解

- 9 - - - 2 - - 1
- - - - 6 - - - 2
- - - - - - 4 - -
6 - - - 8 - - - -
- 2 - - - - - - -
- - 1 7 - 4 - - -
3 6 - - - - - - -
- - 7 - - - 5 - -
9 5 - - - 7 - - 8

字符串转数字 数字转字符串

#include <stdio.h>
void toString(int number, char *str);
void toInt(char *str, int *number);
void main() 
{
    char str1[20],str2[20];
    int number;
    toString(123,str1);
    toString(-123,str2);

    toInt("500",&number);
    printf("%s\n",str1);
    printf("%s\n",str2);
    printf("%d\n",number);
    getchar();
}
void toString(int number,char *str)//数字转字符串算法实现
{
    int isNegative = 0;//默认为非负数
    int i,j;
    char temp;
    isNegative = number < 0 ? (number*=-1,1) :0;//判断是否为负数,巧用逗号表达式,可以省一行(哈哈)
    for (i = 0; number != 0; i++)//反向逐一取得字符,最后反转
    {
        str[i] = (char)(number % 10+48);
        number /= 10;
    }

    if (isNegative)//负数处理
    {
        str[i++] = '-';
        str[i--] = 0;
    }
    else//正数处理
        str[i--] = 0;//i++,可以使得i正好等于字符个数,又省了三行(低调)

    for (j = 0; j <= i / 2; j++)//字符数组反转,3个字符换两次,4个换两次,奇偶通用(数组反转算法)
    {
        temp = str[j];
        str[j] = str[i - j];
        str[i - j] = temp;
    }
}
void toInt(char *str,int *number)//字符串转数字算法实现
{
    int i;
    *number = 0;//强制初始化
    for (i = 0; str[i] != 0; i++)
        *number = (int)(str[i] - 48) + *number * 10;//逐一取字符转换为数字,并升权放入number
}

查找算法

在随机数列中找第 k 小的项

二分查找 : 在有序的数列里找某项