默认分类
只是一个默认分类

解决GPT分区无法安装系统问题

重装系统时遇到:“windows无法安装到这个磁盘。选中的磁盘采用GPT分区形式”。按照提示更换分区格式可以解决问题,但是更换分区格式需要格式化整张磁盘。肯定不能这么做...

要解决这个问题,我们先要需要理清 GPT与MBR、UEFI与BIOS 这几个名词的区别。

磁盘分区格式:GPT与MBR

随着磁盘容量越来越大,传统的MBR分区表(主引导记录)只能识别磁盘前面的2.2TB左右的空间,已经不能满足大容量磁盘的需求。因此,才有了GPT(全局唯一标识分区表)。GPT可以支持无限个分区,微软目前的限定是128个。MBR最多4个主分区,超过4个再分区只能通过逻辑分区。

UEFI与BIOS

Win8以后笔记本默认是UEFI+GPT,想要从GPT磁盘启动,主板的芯片组必须支持UEFIUEFI可用鼠标操作图形界面,不再是枯燥的蓝底白字的英文。另外UEFI减少了BIOS自检的步骤,从而加快了启动时间。

Add Boot Option(添加引导选项)

在选择UEFI后并没有出现U盘,所以我们需要手动添加引导选项。进入BIOS后找到Add Boot Option选项,首先给你想要添加的启动项起个名字,再选择你的U盘后会出现一个文件目录菜单可以逐级选择,有的BIOS需要手动输入路径,efi文件位置在\EFI\BOOT\SHELLX64.efi

最后通过切换引导方式,手动新建启动项解决了问题。

C++ 读取TXT中的数字到vector容器

读取TXT文件中的数字到一个二维vector容器,也可以将vector输出到一个TXT文件中。
这段程序主要有五个函数readFile,split,transToNum,transVector,output

  1. split分割字符串
  2. readFile调用split并返回一个二维字符串向量
  3. transToNum将字符串转换为int或double。
  4. transVector将二维字符串向量转换为二维int或double向量。
  5. output把一维或二维vector输出到txt(文件名默认为output.txt)

使用示例

TXT文件:

1 3.12 3
-1 1 1 3.123 4.11

调用方法:

vector<vector<int> > intData;
getTXTNum("input.txt", intData);
output(intData);

完整程序代码

#include <iostream>
#include <vector>
#include <fstream>
#include <stdlib.h>

using namespace std;

vector<vector<string> > readFile(string filePath, char tag = ' ');

vector<string> split(string inputString, char tag);

template<typename T>
void transToNum(string inputString, T *result);

template<typename T>
void transVector(vector<vector<string> > data, vector<vector<T> > &intData);

template<typename T>
void getTXTNum(string filePath, vector<vector<T> > &data);

template<typename T>
void output(vector<vector<T> > data, const  char* outputName="output.txt");

template<typename T>
void output(vector<T> data, const char* outputName="output.txt");


vector<vector<string> > readFile(string filePath, char tag) {
    ifstream fileReader(filePath.c_str(), ios::in);
    if (!fileReader) {
        cerr << filePath << " not exist!\n";
        exit(1);
    }
    vector<vector<string> > data;
    string linestring;
    while (getline(fileReader, linestring)) {
        data.push_back(split(linestring, tag));
    }
    return data;
}

vector<string> split(string inputString, char tag) {
    int length = inputString.length();
    unsigned int start = 0;
    vector<string> line;
    for (unsigned int i = 0; i < length; i++) {
        string sub;
        if (inputString[i] == tag) {
            sub = inputString.substr(start, i - start);
            line.push_back(sub);
            start = i + 1;
        } else if (i == length - 1) {
            sub = inputString.substr(start, i - start + 1);
            line.push_back(sub);
        }
    }
    return line;
}

char *getType(int x) {
    return (char *) "int";
}

char *getType(double x) {
    return (char *) "double";
}

char *getType(float x) {
    return (char *) "float";
}

template<typename T>
void transToNum(string inputString, T *result) {
    const char *p = inputString.c_str();
    char *type = getType(*result);
    if (type == "int")
        *result = atoi(p);
    else
        *result = atof(p);
}

template<typename T>
void transVector(vector<vector<string> > data, vector<vector<T> > &intData) {
    vector<vector<string> >::iterator iter = data.begin();
    for (; iter != data.end(); iter++) {
        vector<string> line = *iter;
        vector<string>::iterator lineIter = line.begin();

        vector<T> intLine;
        for (; lineIter != line.end(); lineIter++) {
            T result;
            transToNum(*lineIter, &result);
            intLine.push_back(result);
        }
        intData.push_back(intLine);
    }
}

template<typename T>
void getTXTNum(string filePath, vector<vector<T> > &data) {
    transVector(readFile(filePath), data);
}

template<typename T>
void output(vector<vector<T> > data, const  char* outputName) {
    ofstream outTxt;
    outTxt.open("output.txt",ios::trunc);
    int sizeA = data.size();
    for(int i=0;i<sizeA;i++){
        int sizeB = data[i].size();
        for(int j=0;j<sizeB;j++){
            outTxt<<data[i][j]<<" ";
        }
        outTxt<<endl;
    }    
}

template<typename T>
void output(vector<T> data, const char* outputName) {
    ofstream outTxt;
    outTxt.open("output.txt",ios::trunc);
    int sizeA = data.size();
    for(int i=0;i<sizeA;i++){
        outTxt<<data[i]<<" ";
    }
    outTxt<<endl;
}

参考文章:
c++ 读取数值文件到数组中

在怀疑的时代,人们的行动目标要放得长远些

随着信仰之光的暗淡,人们的目光变得越来越短钱,行动的目标似乎似乎就摆在眼前。
...
因此在在怀疑盛行的时代,最可怕的是人们在追逐每天变化的欲望,完全放弃经过长时间努力才能获得的事物,最终无法建立任何伟大、稳定与持久的事业。
如果这样一个民族的社会状况是民主的,那么我所指出的危险还要加剧。

看到这,我松了一口气~

机器怎么学习

机器学习入门,如果上来就看各种算法,什么神经网络,卷积神经网络,我保证你会云里雾里。最好的方法其实是在站在顶层上了解各种概念,不要纠结于具体实现,这样对机器学习有一个整体的概念就不会迷失方向。要不你想参加什么培训班,都可能被忽悠。

人工智能、机器学习与深度学习?

先对这些名词了解。

人工智能 > 机器学习 > 深度学习

人工智能范围很广,只要是能做某些智能活动的程序都是人工智能。人类的智能活动可以是语言、运动、知觉、学习等等,语言对应的就是自然语言处理,运动对应机器人,知觉可以是语音识别,其中的学习就是机器学习了。深度学习是机器学习的一个分支,你应该听说过深度人工神经网络、卷积神经网络等等,这些就属于深度学习,在入门阶段你可以把深度学习理解成多层的神经网络,AlphaGo就用到了深度学习相关算法。

机器如何学习

谈到学习,当然要有老师先训练,即便人类也不可能从一无所知的小孩自学成才,而且学会了公式还要做习题巩固。所以机器学习当然也需要先人为的进行训练,人类学习的训练方式可以是做习题,机器的学习的训练方式就是数据。我们根据数据是否有标签能进一步划分学习方法,这个标签就相当于人类学习用的习题的答案,如果数据都有标签就是监督式学习,没有标签就是无监督式学习,数据有的有标签有的没有那就是半监督式学习。
当然作了题不给我答案,我只能把题目分个类了。

一、无监督式学习

非监督式学习问题可以进一步分为聚类问题和关联问题。(注意聚类与分类的区别,就像化学中的相似相溶原理,自主地想属于自己的集合靠拢;而分类则是我们根据一定的标准进行划区分)

聚类问题:聚类学习问题指的是我们想在数据中发现内在的分组,比如以购买行为对顾客进行分组。
关联问题:关联问题学习问题指的是我们想发现数据的各部分之间的联系和规则,例如购买X物品的顾客也喜欢购买Y物品。
一些流行的非监督式学习算法的例子:

聚类问题的k-means算法
关联规则学习问题中的Apriori算法

二、监督式学习

在监督式学习下,输入数据被称为“训练数据”,每组训练数据有一个明确的标识或结果,如对防垃圾邮件系统中“垃圾邮件”“非垃圾邮件”,对手写数字识别中的“1“,”2“,”3“,”4“等。在建立预测模型的时候,监督式学习建立一个学习过程,将预测结果与“训练数据”的实际结果进行比较,不断的调整预测模型,直到模型的预测结果达到一个预期的准确率。监督式学习的常见应用场景如分类问题和回归问题。

通常,这类预测问题可以用回归模型(regression)进行解决,回归模型定义了输入与输出的关系,输入即现有知识,而输出则为预测。

常见算法有逻辑回归(Logistic Regression)和反向传递神经网络(Back Propagation Neural Network)

理解KMP算法

理解KMP

算法的基本思想是:当出现不匹配时,就能知晓一部分文本的内容,可以利用这些信息避免将指针回退到所有这些已知的字符串之前。

KMP算法很难懂,难在它的具体代码实现十分简洁,简洁得一点都看不出其背后的思想。

所以最好先不要看代码实现,重要的是先理解思想。(注意:下面的“|”只是起辅助作用,并不存在)

ABCAB|00000
ABCAB|D

设想匹配上面一段字符串,我们已经发现第六个字符不匹配,按程序思维来讲,我们可能这次不匹配下次直接向右移动一位继续比较,这是最朴素的想法。

AB|CAB00000
 A|BCABD

但是观察一下我们会发现,既然前面前几个字符已经比较过了,那我们其实可以利用这一点来多移动几位。就像下面:

ABCAB|00000
   AB|CABD

其实这就是KMP算法的思想,很简单不是吗?

KMP算法中的next数组

到现主要问题是,匹配串的相同前后缀长度。

  • "A"的前缀和后缀都为空集,匹配串最大长度为0;
  • "AB"的前缀为[A],后缀为[B],匹配串最大长度为0;
  • "ABC"的前缀为[A, AB],后缀为[C, BC],匹配串最大长度0;
  • "ABCA"的前缀为[A, AB, ABC],后缀为[A, CA, BCA],匹配串最大长度为1;
  • "ABCAB"的前缀为[A, AB, ABC, ABCA],后缀为[B, AB, CAB, BCAB],匹配串最大长度为2;

在讲next数组时,你应该看过教科书或者算法实现,我猜你一定会有些困惑。别怕这篇文章就是要帮你解决这些问题。

其实观察上面,思路已经比较清晰了。
我们定义两个变量imatchLength,其中 i 控制循环,matchLength记录匹配长度。

如果前后缀相同的话,那就在next数组中保存matchLength加一之后的值,再继续检查下一位。一旦发现一位不匹配,那matchLength立即回退到零。

void getNext(char* p,int next[]){  
    int i,matchLength;   
    int pLen = strlen(p); 
    
    next[0] = 0;  
    while (i < pLen){  
        //p[matchLength]表示前缀,p[i]表示后缀  
        if (matchLength == -1 || p[i] == p[matchLength]){  
            ++i;  
            ++matchLength;  
            next[i] = matchLength;  
        }else{  
           // next数组加长一位,matchLength回退到0
            matchLength = next[matchLength];
        }  
    }  
}  

KMP本质

kmp的本质其实就是有限状态机(DFA)。

屏幕快照 2017-04-15 上午11.28.36.png

最初在状态0,然后每次输入新的字符,都会转移到新的状态或者保持旧状态。

评价

在实际应用中,它比暴力算法的优势并不十分明显,因为极少有应用程序需要在重复性很高的文本中查找重复性很高的模式。但该方法的一个优点是不需要再输入中回退。这使得KMP字符串查找算法更适合在长度不确定的输入流(例如标准输入)中查找进行查找,需要回退的算法在这种情况下则需要复杂的缓冲机制。——《算法(第四版)》

未完待续