在看博客的时候发现July编著的《编程之法 面试和算法心得》非常适合自己,故果断买一本仔细研读学习,在此做个记录并实时更新,以备后续之用,再次感谢July老师,非常不错的一本书籍,推荐购买,感谢!!!
附免费高清PDF带书签July编著的《编程之法 面试和算法心得》【建议买一本,方便查看】
https://pan.baidu.com/s/154wjouhTjAFxNjMQZEY01Q 提取码:k3z9
PS:使用编程环境Window7下的VS2015
/*暴力移位法*/
#include
using namespace std;
#include
const int N = 20;
//打印字符串
void print(char *a)
{
int len = strlen(a);
for (int i = 0; i < len; i++)
{
cout << a[i];
}
cout << "\n";
}
//将数组a中前n个元素移动到后面
void move(char *a, int n)
{
int len = strlen(a);
int i;
char ch;
while (n--)
{
ch = *(a + 0);//暂时存放第一个元素
for (i = 0; i < len - 1; i++)
{
a[i] = a[i + 1];
}
a[i] = ch;
}
}
int main()
{
char a[N] = "abcdefghi";
int n;//需要移动的字符数量
//打印原始字符串
cout << "打印原始字符串为:";
print(a);
//移动后的字符串
cout << "请输入需要移动字符数量:n = ";
cin >> n;
move(a, n);
print(a);
system("pause");
return 0;
}
/*三步反转法*/
#include
using namespace std;
#include
const int N = 20;
//打印字符串
void print(char *a)
{
int len = strlen(a);
for (int i = 0; i < len; i++)
{
cout << a[i];
}
cout << "\n";
}
//反转字符串,从字符串的第from到to进行反转
void Reverse(char *a, int from, int to)
{
char ch;
while (from < to)
{
ch = a[from];
a[from++] = a[to];
a[to--] = ch;
}
}
int main()
{
char a[N] = "abcdefghi";
int n;//需要移动的字符数量
int len = strlen(a);
//打印原始字符串
cout << "打印原始字符串为:";
print(a);
//移动后的字符串
cout << "请输入需要移动字符数量:n = ";
cin >> n;
Reverse(a, 0, n-1);//先反转第一组
Reverse(a, n, len-1);//再反转第二组
Reverse(a, 0, len - 1);//最后整体反转
print(a);
system("pause");
return 0;
}
课后习题之单词反转
分析:该题同样是字符串的反转问题,和前面例题不同的是不是单个字符的反转,而是将某些字符串当做一个整体进行反转,所以难点在于如何将某些字符串当做之前例题讲解的单个字符就OK了。想到这里我就想到了字符串数组,问题迎刃而解^_^。
#include
using namespace std;
#include
const int N = 20;
//打印字符串
void print(string a[],int len)
{
for (int i = 0; i < len; i++)
{
cout << a[i] << ' ';
}
cout << "\n";
}
//反转字符串【以独立字符串为整体进行反转】
void Reverse(string a[], int from, int to)
{
string str;
while (from < to)
{
str = a[from];
a[from++] = a[to];
a[to--] = str;
}
}
int main()
{
string a[N];
char ch;
int i = 0;
cout << "请输入原始字符串:";
while ((ch = cin.peek()) != '\n')//cin.peek()函数仅仅是查看,不取出;此处换为cin.get()出错
{
cin >> a[i];
i++;
}
cout << "打印原始的字符串:";
print(a, i);
//反转字符串
Reverse(a, 0, i-1);
cout << "打印反转后的字符串:";
print(a, i);
system("pause");
return 0;
}
求解字符串的长度方法
当a为字符数字时,其真实长度len = strlen(a);当a为string类型时,其真实长度为len = a.length()
https://blog.csdn.net/shiyideliutang/article/details/83010067
https://blog.csdn.net/holly_z_p_f/article/details/85063174
//暴力轮询法
#include
using namespace std;
#include
//判断字符串a中是否全部包含字符串b中的字符
bool StringContain(string a, string b)
{
int n = 0;//存放两个字符串相同的字符数目
//求解字符串的长度方法
//当a为字符数字时,其真实长度len = strlen(a)
//当a为string类型时,其真实长度为len = a.length()
int len1 = a.length(), len2 = b.length();
cout << "字符串a的长度为:" << len1;
cout << ",字符串b的长度为:" << len2 << "\n";
for (int i = 0; i < len2; i++)
{
for (int j = 0; j < len1; j++)
{
if (b[i] == a[j])
{
n++;
break;
}
}
}
if (n == len2)
return true;
return false;
}
int main()
{
string a, b;
cout << "请输入字符串a:";
cin >> a;
cout << "请输入字符串b:";
cin >> b;
if (StringContain(a, b))
cout << "true" << "\n";
else
cout << "false" << "\n";
system("pause");
return 0;
}
//排序后轮询法
#include
using namespace std;
#include
#include //排序函数sort()
//判断字符串a中是否全部包含字符串b中的字符
bool StringContain(string a, string b)
{
sort(a.begin(), a.end());//对字符串a今次那个从小到大排序
sort(b.begin(), b.end());
cout << "按照从小到大的顺序排序后的字符串a为:" << a
<< ",字符串b为:" << b << "\n";
for (int pb = 0, pa = 0; pb < b.length(); pb++)
{
while ( (pa < a.length()) && (a[pa] < b[pb]) )
{
pa++;
}
if ( (pa >= a.length()) || (a[pa] > b[pb]))
return false;
}
return true;;
}
int main()
{
string a, b;
cout << "请输入字符串a:";
cin >> a;
cout << "请输入字符串b:";
cin >> b;
if (StringContain(a, b))
cout << "true" << "\n";
else
cout << "false" << "\n";
system("pause");
return 0;
}
//素数相乘法【该方法有缺陷:素数相乘容易溢出】
#include
using namespace std;
#include
//埃氏筛法求解素数
void get_primer(int primer[], int n)
{
const int Max = 200;//定义最大200的空间,即求解200以内的素数
//先假设都为素数
bool is_primer[Max];//这种方式初始化不行bool is_primer[Max] = { true };
memset(is_primer, true, Max);
is_primer[0] = is_primer[1] = false;//数字0,1不是素数
for (int i = 2; i < Max; i++)//从数字2开始筛选
{
if (is_primer[i])
{
for (int j = 2 * i; j < Max; j += i)
is_primer[j] = false;
}
}
//将筛选后得到的素数存储在素数对应表中,需要存储的数量为n
int j = 0;
for (int i = 2; i < Max; i++)
{
if (is_primer[i])
{
primer[j++] = i;
if (j == n)
break;
}
}
//打印输出得到的素数表
cout << "打印输出得到的素数对应表为:";
for (int i = 0; i < j; i++)
{
cout << primer[i] << " ";
}
cout << "\n";
}
//判断字符串a中是否全部包含字符串b中的字符
bool StringContain(string a, string b)
{
long long sum1 = 1;//这里最开始定义int类型,但是有可能会溢出,造成运算结果出错
//建立素数对应表
int primer[26];
get_primer(primer, 26);
//求解字符串a中字符对应素数的乘积
for (int i = 0; i < a.length(); i++)
{
int x = primer[a[i] - 'A'];
if (sum1 % x)//目的是过滤重复的字符,可以没有这个判断语句
{
sum1 = sum1 * x;
}
}
//判断字符串b对应的素数是否为a对应素数乘积的因子
for (int j = 0; j < b.length(); j++)
{
int y = primer[b[j] - 'A'];
if (sum1 % y)//有余数的话,说明字符串b中含有的字符在a中没有
return false;
}
return true;
}
int main()
{
string a, b;
cout << "请输入字符串a:";
cin >> a;
cout << "请输入字符串b:";
cin >> b;
if (StringContain(a, b))
cout << "true" << "\n";
else
cout << "false" << "\n";
system("pause");
return 0;
}
//位运算法:字符的比较转化为二进制位运算
#include
using namespace std;
#include
//判断字符串a中是否全部包含字符串b中的字符
bool StringContain(string a, string b)
{
int hash = 0;
for (int i = 0; i < a.length(); i++)
{
hash |= (1 << (a[i] - 'A'));//将1左移(a[i] - 'A')位
}
for (int i = 0; i < b.length(); i++)
{
if ((hash & (1 << (b[i] - 'A'))) == 0)
return false;
}
return true;
}
int main()
{
string a, b;
cout << "请输入字符串a:";
cin >> a;
cout << "请输入字符串b:";
cin >> b;
if (StringContain(a, b))
cout << "true" << "\n";
else
cout << "false" << "\n";
system("pause");
return 0;
}
课后习题之变位词
方法一思路分析:用两个数组分别统计两个字符串里每个字符出现的个数,如果完全一致,则是变位词,否则不是。
#include
using namespace std;
#include
//将string类型转化为char*类型
//这里采用指针引用[*&p]的方式改变原来指针,如果改为*p则无法改变原来的指针【本质是值传递】
bool string_char(string str, char *&p)
{
int len = str.length();
p = new char[len*2];//开辟足够大的内存存储
int n = str.copy(p, len, 0);
p[len] = '\0';
if(n == len)
return true;
return false;
}
//统计字符串中各个字符的个数,并存储在数组中
bool Search(string s, string p)
{
int a[128], b[128];
memset(a, 0, sizeof(a));//全部填充为0
memset(b, 0, sizeof(b));
char *sp,*pp;
string_char(s,sp);
string_char(p,pp);
//统计库中字符的个数
while( (*sp) != '\0')
{
a[*sp]++;
sp++;
}
//统计目标串中字符的个数
while( (*pp) != '\0')
{
b[*pp]++;
pp++;
}
return (0 == memcmp(a,b,sizeof(a)));//将数组a,b前sizeof(a)进行比较
}
int main()
{
string s[20];
string p;
int n = 0,num = 0;//存放目标字符串在字符串中的位置以及总个数
cout << "请输入字符串库:";
char ch;
int i = 0;
while( (ch = cin.peek()) != '\n')//向字符串库中存储字符串
{
cin >> s[i];
i++;
}
cout << "请输入目标字符串:";
cin >> p;
//在字符串库中寻找目标字符串
int j = 0;
while(i--)
{
n++;
if( Search(s[j++], p) )
{
cout <<"\n在库中的第" << n << "个位置";
num++;
}
}
if( !num )
cout << "库中不存在"<< "\n";
else
cout << "\n\n库中一共有" << num << "个目标字符串";
return 0;
}
方法二思路分析:利用素数对应表,将每个字母对应相应的素数,然后求解各字符串对应的素数乘积,最终比较两个素数乘积是否相等[是则为兄弟字符串,否则不是]。【程序实现这里不再赘述,和“字母串的包含”专题中的‘素数相乘法’类似】
全排列的递归实现参考文档:
https://blog.csdn.net/lemon_tree12138/article/details/50986990
https://blog.csdn.net/dreamzuora/article/details/52768439
https://blog.csdn.net/morewindows/article/details/7370155
想要上图PDF版本以及更多总结,在这篇博客留下您的邮箱https://blog.csdn.net/shiyideliutang/article/details/100086498,第一时间为您发送。
/**< 递归实现全排列 */
#include
using namespace std;
#include
void CalcAllPermutation(char *a, int from, int to)
{
if( to <= 1)
return;
if(from == to)//递归结束条件
{
for(int i = 0; i <= to; i++)
cout << a[i];
cout << "\n";
}
else
{
for(int j = from; j <= to; j++)
{
//交换两个变量
swap(a[j], a[from]);//swap()函数为STL库的函数,声明为swap(ElemType &a, ElemType &b)引用传递
CalcAllPermutation(a, from+1, to);
swap(a[j], a[from]);
}
}
}
int main()
{
string str;
cout << "请输入一串字符串:";
cin >> str;
//原始打印字符串
cout << "字符串的原始打印输出为:" << str << "\n";
//输出原始字符串的全排列
cout << "-------输出原始字符串的全排列-------\n";
char *data;
int len = str.length(), n;
//开辟足够大的空间来存储
data = new char[len*2];//在C语言中为:data = (char *)malloc((len * 2)*sizeof(char));
n = str.copy(data, len, 0);//返回真实复制的字符数量
if(n == len)//检验一下
{
data[len] = '\0';
CalcAllPermutation(data, 0, len-1);//因为这里string类型无法直接传递给char *类型,所以前面需要先转化一下。
}
return 0;
}
//直接利用STL中的库函数next_permutation来做,库函数对于有重复字符出现时也适用
#include
#include
#include
using namespace std;
char str[1000];
int main()
{
cout << "Please input astring:";
cin>>str;
sort(str,str+strlen(str));//先排序
//从stl库中调用全排列的库函数
do
{
for(int i=0;i
课后举一反三暂时未做
//自己做的答案
#include
using namespace std;
#include
#include
double StrToInt(const char *str)
{
double sum = 0, sum1 = 0;
int len = strlen(str);//字符串的实际长度
for(int i = len-1; i >=0; i--)
{
//由于pow函数声明为“ double pow(double x, double y);”所以定义sum务必注意,定义为int会出错。
sum = sum + (*str - '0') * pow(10,i);
str++;
}
return sum;
}
int main()
{
char str[100];
cin >> str;
double sum = StrToInt(str);
cout.setf(ios_base::floatfield, ios_base::fixed);//定点数显示
cout.precision(1);//因为上一条语句设置为定点数显示,所以这里精度为小数点后的位数。
cout << "转化为整数是:" << sum << endl;
return 0;
}
pow函数原型为: double pow(double x, double y);所以在存储其结果时候需要谨慎一点最好声明为double类型,否则有时候会无端端的出错。
//考虑较为全面的思路,除了溢出条件未考虑
#include
using namespace std;
#include
#include
int StrToInt(const char*str)
{
int n = 0;
//判断输入是否为空
if (str == 0)
return 0;
//处理空格
while (isspace(*str))
str++;
//处理正负
int sign = 1;
if (*str == '-')
{
sign = -1;
str++;
}
//正式处理转化
while (isdigit(*str))
{
int c = *str - '0';
n = n * 10 + c;
str++;
}
return sign>0? n:-n;
}
int main()
{
string str;
const char* str1;
cout << "请输入一串数字串:";
cin >> str;
str1 = str.data();//因为函数的参数为char*类型,所以需要提前转化一下。
int sum = StrToInt(str1);
cout << "最终转化的数字为" << sum << "\n\n";
system("pause");
return 0;
}
回文正着看和反着看都一样。
//从两边往中间扫描遍历,进行比较
#include
using namespace std;
#include
//判断输入输入的字符串是否为回文系列
bool is_HuiWen(char *str)
{
int len = strlen(str);//字符串的实际长度
char *head = str;//头指针
char *tool = str + len-1;//尾指针[注意这里需要减去1]
//判断意外输入的情况
if(str == NULL)
return false;
//从两边到中间判断
while (head <= tool)
{
if (*head != *tool)
return false;
head++;
tool--;
}
return true;
}
int main()
{
string str;
cout << "请输入一串字符串:";
cin >> str;
//将string类型转化为char*类型
int len = str.length();
char *data;
data = new char[2*len];
str.copy(data, len, 0);
data[len] = '\0';
//判断是否为回文序列
if (is_HuiWen(data))
cout << str << "是回文序列" << '\n';
else
cout << str << "不是回文序列" << '\n';
return 0;
}
//从中间往两边扫描遍历,进行比较
#include
using namespace std;
#include
//判断输入输入的字符串是否为回文系列
bool is_HuiWen(char *str)
{
int len = strlen(str);//字符串的实际长度
int n = ((len>>1) - 1) >= 0? ((len>>1) - 1):0;//注意右移运算的优先级低于算术运算符
char *left = str + n;//左指针
char *right = str + len-1 - n;//右指针
//判断意外输入的情况
if(str == NULL)
return false;
//从中间到两边判断
while ( left >= str)
{
if (*left != *right)
return false;
right++;
left--;
}
return true;
}
int main()
{
string str;
cout << "请输入一串字符串:";
cin >> str;
//将string类型转化为char*类型
int len = str.length();
char *data;
data = new char[2*len];
str.copy(data, len, 0);
data[len] = '\0';
//判断是否为回文序列
if (is_HuiWen(data))
cout << str << "是回文序列" << '\n';
else
cout << str << "不是回文序列" << '\n';
return 0;
}
举一反三之链表回文
参考文档:https://blog.csdn.net/heyabo/article/details/7610732
/*******辅助指针、递归方法实现单链表的逆置*********/
#include
using namespace std;
typedef char ElemType;
typedef int Status;
#define OK 1
#define ERROR 0
//定义链表的存储结构
typedef struct Node
{
ElemType data;
struct Node* next;
}Node, *LinkList;
//初始化单链表
Status InitList(LinkList *L)
{
*L = new Node;
if(*L == NULL)
return ERROR;
(*L)->next = NULL;
return OK;
}
//求解单链表中的数据长度
int Length(LinkList L)
{
int i = 0;
LinkList p = L->next;//指向第一个结点
while(p)
{
i++;
p = p->next;
}
return i;
}
//打印输出有头结点的单链表
void print(LinkList L)
{
LinkList p = L->next;//指向第一个结点
while(p)
{
cout << p->data << " ";
p = p->next;
}
cout << '\n';
}
//打印输出无头结点的单链表
void print2(LinkList L)
{
LinkList p = L;//指向第一个结点
while(p)
{
cout << p->data << " ";
p = p->next;
}
cout << '\n';
}
//初始化创建单链表
void CreatList(LinkList *L, int n)
{
LinkList p,r;
*L = new Node;
r = *L;
cout << "请输入单链表的数据元素:";
for(int i =0; i < n; i++)
{
p = new Node;
cin >> p->data;
r->next = p;
r = p;
}
r->next = NULL;
}
//逆置单链表[利用辅助指针的方法]
void Reverse(LinkList *L)
{
cout << "将单链表逆置ing!!!" << "\n";
if((*L) == NULL || (*L)->next == NULL)//判断链表是否为空表
return;
LinkList pPre = NULL;//先前指针
LinkList pCur = (*L)->next;//当前指针
LinkList pNext = NULL;//后继指针
while(pCur != NULL)
{
pNext = pCur->next;
pCur->next = pPre;
//重现定义指针类型[下面两句顺序不可以颠倒]
pPre = pCur;
pCur= pNext;
}
(*L)->next = NULL;//头结点作为了最后一个结点,指向NULL
//记录新的头结点
*L = pPre;
}
//逆置单链表[利用递归的方法]
void Reverse2(LinkList *L, LinkList pCur)
{
if(pCur == NULL || pCur->next == NULL)
*L = pCur;
else
{
LinkList pNext = pCur->next;
Reverse2(L, pNext);
pNext->next = pCur;
pCur->next = NULL;
}
}
int main()
{
LinkList L;
InitList(&L);//初始化单链表
int n;
cout << "请输入单链表的长度:";
cin >> n;
CreatList(&L,n);//创建单链表
int len = Length(L);
cout << "单链表的长度为" << len << "\n";
cout << "原始打印输出的单链表为:";
print(L);//打印输出单链表
//逆置单链表[辅助指针法]
Reverse(&L);
cout << "单链表逆置[辅助指针法]后打印输出为:";
print2(L);//打印输出单链表[这里单链表不存在头结点]
//逆置单链表[递归法]
Reverse2(&L, L);
cout << "单链表逆置[递归法]后打印输出为:";
print2(L);//打印输出单链表[这里单链表不存在头结点]
return 0;
}
举一反三之栈回文
/*********自做答案*********/
#include
using namespace std;
#include
//【中心扩展法】寻找最长回文子串
void Search(const char *str, int *num)
{
int len = strlen(str);
if(len == 1)
return;
else if(len == 2)
{
if(*str == *(str+1))
*num = 2;
}
else
{
const char *p = str+1;
char const *temp1,*temp2;//char const和const char无区别
int num_temp = *num;
while(p < str+len)
{
//针对回文子串为奇数个的情况
temp1 = temp2 = p;
while(temp1 > str && temp2 < str+len)
{
temp1--;
temp2++;
if(*temp1 == *temp2)
num_temp++;
else
break;
}
if(num_temp > *num)
{
*num = num_temp*2 + 1;
num_temp = 0;
}
//针对回文子串为偶数个的情况
temp1 = p;
temp2 = p+1;
while(temp1 >= str && temp2 <= str+len)
{
if(*temp1 == *temp2)
num_temp++;
else
break;
temp1--;
temp2++;
}
if(num_temp > *num)
{
*num = num_temp*2;
num_temp = 0;
}
p++;
}
}
}
int main()
{
string str;
int num = 0;//存储最长回文子串的长度
cout << "请输入一串字符串:";
cin >> str;
Search(str.data(), &num);//string类型转换
if(!num)
cout << "不存在回文串";
else
cout << "最长回文子串的长度为:" << num << endl;
return 0;
}
/*********参考答案*********/
#include
using namespace std;
#include
//【中心扩展法】寻找最长回文子串
void Search(const char *str, int *num)
{
int len = strlen(str);
int num_temp = 0;
//回文中心从0依次遍历到len
for(int i = 0; i <= len; i++)
{
//回文长度为奇数
for(int j = 0; (i-j)>=0 && (i+j) <= len; j++)
{
if(str[i-j] != str[i+j])
break;
num_temp = 2*j + 1;
}
if(num_temp > *num)
*num = num_temp;
//回文长度为偶数
for(int k = 0; (i-k)>=0 && (i+k+1) <= len; k++)
{
if(str[i-k] != str[i+k+1])
break;
num_temp = 2*k + 2;
}
if(num_temp > *num)
*num = num_temp;
}
}
int main()
{
string str;
int num = 0;//存储最长回文子串的长度
cout << "请输入一串字符串:";
cin >> str;
Search(str.data(), &num);//string类型转换
if(!num)
cout << "不存在回文串";
else
cout << "最长回文子串的长度为:" << num << endl;
return 0;
}
https://blog.csdn.net/weixin_42373330/article/details/82118694
#include//使用C语言中的函数:scanf,printf
#include
#include
#include
#include
using namespace std;
#define ll long long
char str[2010];
int p[2500];
int main()
{
while(scanf("%s",str)==1)//字符数组的输入也可以像string类型那样整体输入
//当str定义为string类型时候,可以使用:cin >> str输入,但是又不方便单个元素的取用
//这里这种方法既可以保证输入时候像string类型方便,也可保证使用时像char数组类型方便
{
int len=strlen(str);
memset(p,0,sizeof(p));
//预处理
for(int i=len;i>=0;i--)
{
str[2*i+2]=str[i];
str[2*i+1]='#';
}
str[0]='$';
//初始化“马拉车算法”的一些定义量
int mx=0;
int id=0;
int res=0;
for(int i=0;i<=2*len+1;i++)
{
if(mx>i)
p[i]=min(p[2*id-i],mx-i);
else
p[i]=1;
while(str[i-p[i]]==str[i+p[i]])
p[i]++;
if(i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
}
//输出P数组
for(int i=0;i<=2*len+1;i++)
printf("%d ",p[i]);
printf("\n");
}
return 0;
}