borland style
关于常识: 1、参数为指针类型,为了鲁棒性,就要首先判断指针是否NULL, ---若函数返回值不是bool或者int型或者指针类型,则就判断指针不为NULL; ---若函数返回值是bool或者int型或者指针类型,则就判断指针为NULL; 参数为vector<int> array,则需要计算出int len = array.size(),然后判断len的大小,从而实现鲁棒性 2、二维数组的行和列 ---若用一维数组存放二维数组时,则前提必须已知行rowCount和列colCount; ---若用vector<vector<int>> array保存二维数组时,行数为rowCount = array.size(), 列数为colCount = array[0].size(); 3、关于链表常识 //链表是一种动态数据结构,再创建链表时,无需知道链表的长度。 //插入链表时,分配内存(每添加一个)--调整指针指向---使其插入到链表中。 //遍历链表是从头结点遍历的,但是要备份头结点,用临时结点去遍历 //首先必须会定义一个链表 struct ListNode { int val; struct ListNode *next; }; 4、关于树的常识 ---首先定义一个二叉树的结点 struct BinaryTreeNode { int value; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight; }; 然后定义保存树的容器--前序和结束的容器,中序和结束容器; 创建二叉树,定义二叉树的头结点指针 { TreeNode* root = new TreeNode();//根据构造函数确定形式 root->val = rootValue; root->left = root->right = NULL; } 5、vector容器是可以直接用下标进行索取元素; 6、参数是指针类型表示--用指针充当数组,前提必须知道数组长度 7、递归和函数调用的区别 递归由于函数调用自身,而函数调用是有时间和空间的消耗的---每一次函数调用都需要在内存栈中分配空间以保存参数、返回地址及临时变量,而且往栈中压入数据和弹出数据都需要时间。 因而递归实现的效率就不如循环。 递归中有可能很多计算是重复的,从而对性能带来很大的负面影响。递归的本质---是把一个问题分解成2个或者多个小问题,如果多个小问题存在相互重叠部分,那么就存在重复的计算。 递归可能出现栈溢出。每一次函数调用在内存栈中分配空间,而每个进程的栈的容量是有限的。当递归调用的层级太多时,就会超出栈的容量,从而导致调用栈溢出。 8、如何定义一个二维数组 int **doubleArray; int num = 6; doubleArray = new int*[num]; for(int i = 0; i<num; i++) { doubleArray[i] = new int[num]; } 9、求斐波那契数列时,从最小开始计算,然后总结规律推导出通用公式,然后就可以直接写出代码。通用公式为最简公式。 10、位运算符 左移运算符<< --m<<n表示把m左移n位,最左边的舍弃,右边补0 右移运算符>> --m>>n表示把m右移n位,最右边的舍弃,左边的分情况; --若数字是一个无符号数值,用0填补最左边的n位, --若数字是一个有符号数值,用数字的符号位填补最左边的n位。 11、判断两个浮点数是否相等或者一个浮点数是否等于0 double num1, num2; if(num1-num2 > -0.0000001 && num1 - num2 < 0.0000001) { return true; } return false; 12、判断一个数是否是奇数和偶数,要用与运算符 int count = num; 判断它不是偶数--(num & 0x1)!= 0; 判断它不是奇数--(num & 0x1)== 0; 13、一维指针若是表示一维数组,则数组的起始位置和终端位置表示如下: int *pData; int length;//数组的长度 int *pBegin = pData; int *pEnd = pData + length -1; 14、vector使用元素时,不仅可以用下标运算符指定某一元素,而且还可以使用迭代器指向某一元素。 最好使用迭代器,因为要使用vector的操作时,很多参数类型都是迭代器。例如erase(iteator类型) 15、 vector<int>::iterator pEnd = array.end(); while(pBegin != array.end())//注意此处不可以用pEnd代替array.end()。否则会发生栈溢出。 { pBegin = array.erase(pBegin);//erase会造成迭代器pEnd失效,故不能将array.end()等同 } 16、关于队列,判断条件是否为空 while(!queue.empty()) 队列的头元素为queue.front() 17、清除vector的内存,应该用swap()而不是clear()操作。 18、实现代码的通用性,在判断奇数和偶数、正负数排序等时,记得用函数指针 typedef bool (*func)(int); bool isEven(int n) { return (n & 1) != 0; } func = isEven; func(5); 19、对链表进行遍历时;要判断链表结点的下个结点是否为空 for (int i = 0; i < k-1; ++i) { if (pAhead->next != NULL) { pAhead = pAhead->next; } else { return NULL; } } 20、什么是尾结点?自然是next为NULL的时候。 21、对链表进行遍历操作时,要对链表进行移动操作,要注意将当前节点转为先前节点,下一个节点转为当前节点 while(pNode != NULL) { ListNode* pNext = pNode->next; if (pNext == NULL)//表示只有头结点的时候 { pReverseHead == pNode;//反转链表的头结点就是之前的头结点 } pNode->next = pPrev;//当前结点的方向反转 pPrev = pNode;//当前结点变成了之前的结点 pNode = pNext;//下一个节点变成了当前节点1 } 22、注意递归的时候,不需要备份节点然后进行使用以及返回, 但是转为循环的时候,必须将遍历的节点进行备份,然后返回源节点 23、看到树,二话不说,先建立树节点的结构 struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; TreeNode(int x):val(x), left(NULL), right(NULL) { } }; 24、首先考虑的就是范围,应该定义为long类型。关于表达一个大数问题,最常用的方法就是用字符串或者数组表达大数。 25、如何在字符串表达的数字上模拟加法,二是把字符串表达的数字打印出来。 字符串中的个位+1操作; bool Increment(char* number) { bool isOverFlow = false;//是否溢出 int nTakeOver = 0; int nLength = strlen(number); for (int i = nLength-1; i >= 0; --i) { int nSum = number[i] - '0' + nTakeOver;//当前位+进位标识符 if (i == nLength-1) { nSum++; } if (nSum >= 10)//最低位大于10 { if (i == 0) { isOverFlow = true;//已经达到最大值 } else { nSum -= 10; nTakeOver = 1;//进位标识符 number[i] = '0'+nSum; } } else { number[i] = '0'+nSum; break; } } return isOverFlow; } 26、如何打印用字符串表示的数字。 void PrintNumber(char* number) { bool isBegining0 = true; int nLength = strlen(number); for (int i = 0; i < nLength; ++i) { if(number[i] != '0') { printf("%c", number[i]); } } } 如何将字符串转为数字 for(int i=(str[i]=='-'||str[i]=='+')?1:0;i<len;++i) { if(!(str[i]>='0'&&str[i]<='9'))//不在范围内的返回0 { return 0; } result=result*10+str[i]-'0';//范围内的字符转换为整数 } 27、如何用在堆上创建一个n维数组 char* number = new char[n+1]; number[n] = '\0'; 但是别忘了 delete[] number; 28、 关于如何使用递归策略来处理程序? 1、结束条件---递归什么时候结束; 2、非结束的条件--如何由情况n变成情况n+1,即非结束的条件, 3、初始条件---递归调用以什么样的初始条件开始。 综上,写出一个递归函数。 数学归纳法,对使用递归很重要。 不要试图去解决问题,而只解决n=1的问题。 29、如果链表中只有一个节点,我们要删除链表的头结点也是尾结点,此时我们再删除节点之后,还要把链表的头结点设置为NULL。 30、遇到栈,首先要定义栈,然后再做辅助栈 stack<int> mStack; 备份栈 stack<int> tmpStack; 一般循环结束条件尾mStack.size()或者mStack.empty() 31、先进先出原则,要考虑到队列,循环结束条件通常是 queue<元素的类型> mQueue; mQueue.size(), mQueue.empty() 32、通常将栈和队列作为辅助的时候,循环结束条件通常是.empty() 33、看见树,想到分左右,左右就要想到递归操作。 34、首先了解什么是路径? 路径是从根节点出发到叶节点,也就是说路径总是从根节点为起始点,因此需要首先遍历根节点。 从而选择前序遍历。保存路径的一个数据结构就是一个栈。 对路径查找的时候,若不满足条件,记得要删除其之前的结点,然后进行另一子节点操作。 35、分治法:就是把分解之后的小问题各个解决。然后把小问题的解决方案结合起来来解决大问题。 通常分治法思路都可以用递归的代码来实现。 36、将二叉搜索树转换成排序的双向链表。 根节点、左子树和右子树。在把左、右子树都转换成排序的双向链表之后,再和根节点链表起来,整棵二叉搜索树也就转换成了排序的双向链表。 常识:由于遍历和转换过程是一样的,故可以想到递归。 37、补充树递归的思路:先遍历左子结点,然后递归到最底层之后,对其进行处理操作。然后递归层层返回,然后到根节点,再多根节点进行操作(就是左子结点遍历后的操作,不需要重新写)。最后再处理右子结点。 38、若参数类型是string,则鲁棒性代码是 if(string.size()==0) { return ""; } 或者也可以使用 if(string.empty()) { return ""; } 39、对组合进行排序的时候,输出结果注意要全排序。 容器中string类型有排序操作sort(迭代器1,迭代器2) 40、对于一个链表进行遍历即操作的时候 步骤如下: 先判断条件---头结点的下一个结点是否为NULL 再将循环条件的结点进行备份, 再做相应处理的操作; 然后将备份结点改变成当前要处理的结点; 41、成熟的O(n)算法--Partition函数的O(n)的算法--得到数组中任意第K大的数字 找任意的第K大的数字,就要想到快排。 int index = Partition(array[], n, int start, int end); while(index != K-1) { if(index > k-1) { end = index-1; Partition(array[],n, start, end); } else { start = index+1; Partition(array[], n, start, end); } } 42、在定义函数参数的时候,记得要用引用类型。 partion(vector<int>& input, int beg, int end) 43、使用vector容器的时候,添加元素的时候,不要总是使用push_back(); 还可以使用迭代器, 例如:vector<int> tmpVec(input.begin(), input.begin() + k); 44、 常识:想到二叉树来解决问题,就要想到用什么二叉树为好? 如该题就是每次都需要找到K个整数中最大的数字,很容易想到最大堆。在最大堆中,根节点的值总是大于它的子树中任意结点的值。 最大堆常识--在O(1)得到已有的K个数字中的最大值,但需要O(logk)时间完成删除和插入操作。 也可以用红黑树来代替最大堆来实现容器。红黑树通过把结点分为红黑两种颜色并根据一些规则确保树在一定程度上是平衡的,从而保证在红黑书中查找、删除和插入都只需要O(logk)时间。 44、 typedef multiset<int, greater<int>> intset; typedef multiset<int ,greater<int>>::iteator setIterator; intset hasKDigits; 使用set或者map中最好先类型别名,然后在定义容器以及迭代器。使用容器之前,先对容器进行清空操作。 hasKDigits.insert(元素),插入操作; hasKDigits.erase(迭代器),删除操作; 45、当返回类型是vector<int>时,处理鲁棒性问题的时候,可以在函数中 写return{} 或者写成return vector<int>{} 46、在STL中有sort算法---该算法的时间复杂度为O(nlogn) --在一些容器中常用,vector sort(迭代器1,迭代器2),对[迭代器1, 迭代器2)进行排序操作 47、不要总是使用push_back,来对vector进行填充,还可以使用初始化方式和迭代器进行操作 返回匿名vector return vector<int>(hasKDigits.begin(), hasKDigits.end()) 48、 在条件判断语句中,不要 // iterEnd = iter.end(); // if(iter != iterEnd);而应该写成if(iter!=iter.end()) // 原因,是因为你在循环条件语句中做迭代器操作,会使迭代器失效。 if (*iter < *(hasKDigits.begin())) 尽量不要写if (*iter < *(iterGreatest)) //原因,在set容器中被删除的迭代器会失效。即不能使用erase(iter++),而应该使用 //for( iter = c.begin(); iter != c.end(); ) //iter = c.erase(iter); return {};可以写成return vector<int>(); 49、使用STL中的最大堆时 建立堆,首先要堆原始数据进行备份,通过备份数据建立堆 vector<int> res(input.begin(),input.begin()+k); //建最大堆 make_heap(res.begin(),res.end()); //在堆中删除数据--要先调用pop_heap,再在容器中删除数据 pop_heap(res.begin(),res.end()); //在堆中添加数据-要先在容器中加入数据,再调用push_heap () push_heap (_First, _Last) //堆排序--排序之后就不再是一个合法的heap了 sort_heap(_First, _Last) 最小堆 min.push_back(num); push_heap(min.begin(), min.end(), greater<int>()); 最大堆 max.push_back(num); push_heap(max.begin(), max.end(), less<T>()); 50、如何将本次循环与上次循环的结果进行比较,做取舍? int maxSum =array[0] ; int result = array[0]; if (result > maxSum ) { maxSum = result; } 51、判断一个数的个位是不是1,通过对10求余数进行判断。 52、sprintf(strN, "%d", n);把整数n打印成一个字符串保存在strN中 eg://把整数123 打印成一个字符串保存在s 中。 sprintf(s, "%d", 123); //产生"123" 可以指定宽度,不足的左边补空格: sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567" 当然也可以左对齐: sprintf(s, "%-8d%8d", 123, 4567); //产生:"123 4567" 也可以按照16 进制打印: sprintf(s, "%8x", 4567); //小写16 进制,宽度占8 个位置,右对齐 sprintf(s, "%-8X", 4568); //大写16 进制,宽度占8 个位置,左对齐 53、atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数 54、 C++ 排序函数 sort(),qsort()的用法 ---Sort(start,end,排序方法) ---void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*)); 各参数:1 待排序数组首地址 2 数组中待排序元素数量 3 各元素的占用空间大小 4 指向函数的指针 55、函数原型: string to_string (int val); string to_string (long val); string to_string (long long val); string to_string (unsigned val); string to_string (unsigned long val); string to_string (unsigned long long val); string to_string (float val); string to_string (double val); string to_string (long double val); 功能: 将数值转化为字符串。返回对应的字符串。 56、MIN(number1,number2, ...)Number1, number2,... 是要从中找出最小值的 1 到 30 个数字参数。 57、vector<int> tmpVec(index);//分配容器大小,并初始化为0 58、三个有序组合成一个有序数组思想很好 tmpVec[i] = min(tmpVec[t2]*2, min(tmpVec[t3]*3, tmpVec[t5]*5));//保存丑数 if (tmpVec[i] == tmpVec[t2]*2) { t2++; } if (tmpVec[i] == tmpVec[t3]*3) { t3++; } if (tmpVec[i] == tmpVec[t5]*5) { t5++; } 59、string类型 if (str == "") { return -1; } 或者 if (str.empty()) { return -1; } 60、 举例: map<char, int> hash1; for (auto x : hash1) { if (x.second == 1) { if (hash2[x.first] < min_index) { min_index = hash2[x.first]; } } } 基于范围的for循环后的括号由冒号“:”分为两部分,第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。 注意:auto不会自动推导出引用类型,如需引用要加上& auto& :修改 auto:不修改, 拷贝对象 基于范围的循环在标准库容器中时,如果使用auto来声明迭代的对象的话,那么该对象不会是迭代器对象,而是解引用后的对象。 continue与break的作用与原来的for循环是一致的。 使用条件: (1)for循环迭代的范围是可确定的:对于类,需要有begin()与end()函数;对于数组,需要确定第一个元素到最后一个元素的范围; (2)迭代器要重载++; (3)迭代器要重载*, 即*iterator; (4)迭代器要重载== / !=。 对于标准库中的容器,如string, array, vector, deque, list, queue, map, set,等使用基于范围的for循环没有问题,因为标准库总是保持其容器定义了相关操作。 注意:如果数组大小不能确定的话,是不能使用基于范围的for 循环的。 61、 INT_MAX = 2147483647 INT_MIN = -2147483648 62、如何在堆上定义一个内存 int *space =(int*)malloc(sizeof(int)max); 如何求出一个数组的长度 int array[] = {1,2,3,4,5,6}; int len = sizeof(array)/sizeof(*array); 63、当出现2个链表的时候,记得用两个指针分别进行对齐遍历和比较。 或者是求两个链表长度之差。然后让长的先遍历--两个链表长度之差,短的后遍历。 64、已知数组是排序的,则马上要想到二分查找。 65、如果用递归对数组进行操作,前半段和后半段 则若参数类型是指针类型,则就已知长度,以及开始和末尾参数 若参数类型是vector<int> ,则不需要知道容器的长度,但是要知道开始和末尾的下标参数。 66、二分查找先操作,在递归 组合先递归在操作 67、与或一起操作的时候要记得带括号 68、如何将上次结果与这次结果比较,保存最大值 maxSum = INT_MAX; for(int i=0; i<length; i++) { if (result > maxSum ) { maxSum = result; } } 69、一个(或者两个)数字只出现一次,其他的出现两次。要想到异或运算的性质。 任何一个数字异或自己都是0. 也就是说我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次数字,因为那些成对出现2次的数字全部都异或中抵消了。 class Solution 70、 思想:small增加到下标为(总和+1)/2,因为big始终大于small。 如果small = (总和+1)/2, big = (总和+1)/2+1; 则small + big > 总和 输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序 如果从small到big的序列和大于S,我们可以从序列中去掉较小的值,也就是增大small的值。如果从small到big的序列的和小于S,我们可以增大big,让这个序列包含更多的数。因为这个序列至少要两个数,我们一直增加Small到(1+s)/2 71、求一个指针指向的字符串的长度 比如char* str; 则长度位int len = static_cast<int>(strlen(str)); 72、关于字符串string类型,要使用其做参数且对其字符进行操作,则要求参数必须有下标类型; string Reverse(string str, int start, int end); 关于是char* str类型,要对字符串进行操作,只需要知道字符串的开始位置和结束位置即可。 开始位置表示为char* pBegin = str; 结束位置表示为char* pEnd = str+n-1; 73、 string类的size()/length()方法返回的是字节数 没有区别 74、如何使用STL中的排序问题呢? 若是指针类型 int *numbers; void IsContinue(int* numbers, int length) qsort(numbers, length, sizeof(int), compare); int compare(const void* arg1, const void* arg2) { return *(int*)arg1-*(int*)arg2; } 若是vector类型 void IsContinue(vector<int> numbers) { sort(numbers.begin(), numbers.end()); } 75、在堆上创建数组 int *numbers = new int[6*number-number+1]; 76、pow的用法 int gMaxValue, number; int total = pow((double)gMaxValue, number); 77、printf的用法 printf("%d: %e\n", i, radio ); 78、有一个圆圈,要想到用数据结构来模拟这个圆圈。在常用的数据结构中,很容易想到环形链表。 79、list中也有push_back操作。 迭代器.begin(),也满足++运算 如何将一个单链表变成一个环状链表 for (int i = 1; i < m; ++i) { current++; if (current == numbers.end()) { current = numbers.begin(); } } 80、如果一个映射为p(x) = (x-k-1)%n,它映射前的数字是x,那么映射后的数字是(x-k-1)%n, 则逆映射'p'(x) = (x+k+1)%n 81、如果对n连续做两次反运算,即!!n。那么非0的n转换为true,0转换成false。 82、//-------利用虚函数求解------------ //定义2个函数:一个函数中判断是不是应该终止递归,那么我们不放定义两个函数,一个函数充当递归函数的角色,另一个函数处理终止递归的情况,我们需要做的就是再两个函数里二选一。从二选一想到布尔变量。 //在true(1)的时候调用第一个函数,值为false(0)的时候调用第二个函数。那么现在的问题是如何把数值变量n转换成布尔值。如果对n连续做两次反运算,即!!n。那么非0的n转换为true,0转换成false。 class A; A* Array[2]; class A { public: virtual unsigned int Sum(unsigned int n) { return 0; } }; class B:public A { public: virtual unsigned int Sum(unsigned int n) { return Array[!!n]->Sum(n-1)+n; } }; class Solution { public: friend class A; friend class B; int Sum_Solution(int n) { A a; B b; Array[0] = &a; Array[1] = &b; int value = Array[1]->Sum(n); return value; } }; 83、 //-------利用逻辑运算的短路特性-------- //逻辑运算的短路特性: //(表达式1)&&(表达式2) 如果表达式1为假,则表达式2不会进行运算,即表达式2“被短路” //(表达式1)||(表达式2) 如果表达式1为真,则表达式2不会进行运算,即表达式2“被短路” class Solution { public: int Sum_Solution(int n) { int ans = n; ans && (ans+=Sum_Solution(n-1)); return ans; } }; 84、如何使用函数指针 定义的函数指针可以充当函数返回类型。即使用函数指针的时候将其当作普通类型对待即可 typedef int (*func)(int); int Solution3_Teminator(int n) { return 0; } int Sum_Solution(int n) { func f[2] = {Solution3_Teminator,Sum_Solution}; return n + f[!!n](n-1); } 85、二进制进位操作 carry = (num1 & num2) << 1; 不产生进位结束条件while(carry != 0) 关于两个数相加,不用四则运算 先用异或,各位相加不算进位;然后各位相与再向左移位。 重复上述步骤即可。 86、substr是C++语言函数,主要功能是复制子字符串,要求从指定位置开始,并具有指定的长度。如果没有指定长度_Count或_Count+_Off超出了源字符串的长度,则子字符串将延续到源字符串的结尾。 basic_string substr(size_type _Off = 0,size_type _Count = npos) const; 参数_Off---所需的子字符串的起始位置。字符串中第一个字符的索引为 0,默认值为0. _Count----复制的字符数目 返回值----一个子字符串,从其指定的位置开始 eg:str = str.substr(1);//返回一个子字符串,从下标位1的位置开始 87、遍历一个string类型字符串,不仅可以用下标操作,也可以用到范围for循环 for (auto d : str)//d就是string字符串中的某个字符 { if(d>='0' && d<='9') { res = res*10 - d -'0'; } else { res = 0; break; } } 同时也可以将string类型转为char*类型来做相应的处理 88、利用枚举类型来标记状态 enum Status{kInValid,kValid} int gStatus = kValid; 初始化的时候为有效状态,进入循环之后将其设置为无效状态 定义一个全局变量来判断是否遇到了非法输入。如果输入的字符串指针是空指针,则标记该全局变量然后直接返回。 89、正整数的最大值位0x7FFF FFFF,最小负整数0x8000 0000 90、记住链表也是有迭代器得 TreeNode* GetLastCommonNode(const list<TreeNode*>&path1, const list<TreeNode*>&path2) { list<TreeNode*>::const_iterator iterator1 = path1.begin(); list<TreeNode*>::const_iterator iterator2 = path2.begin(); TreeNode* pLast = NULL; while(iteator1 != path1.end() && iterator2!= path2.end()) { if (*iterator1 == *iterator2) { pLast = *iterator1; } iterator1++; iterator2++; } return pLast; } 91、 //前序遍历,将树得结点(根节点外)都保存到容器vector<>中,然后使用得带起,进行遍历。 vector<TreeNode*>::iterator i = pRoot->m_vChildren.begin(); 92、对于vector定义对象的时候,记得要初始化,分配一定的容量。 vector<int> tmpVec1(len,1); vector<int> tmpVec2(len,1); 93、关于string类型如何转化位char*类型 string str; const char *p = str.c_str(); 这个是获取常量字串 string str; char *p = new char[str.length()+1](); strcpy(p, str.c_str()); 这个获取可修改缓冲区 94、参数是char*类型 bool match(char* str, char* pattern) { if (pattern[0] == 0 && str[0] == 0) { return true; } } 循环判断条件,是判断*str == '\0'或者 *str !='\0' 95、正则表达式 思路: 当模式中的第二个字符不是"*"时: 1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。 2、如果字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。 当模式中的第二个字符是"*"时: 1、如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。 2、如果字符串第一个字符跟模式第一个字符匹配,可以有3中匹配方式: 1、模式后移2个字符,相当于x*被忽略; 2、字符串后移1字符,模式后移2字符; 3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位; 96、使用map红黑树的时候,可以使用下标运算符, 97、对于一个数组进行初始化 可以利用for循环 unsigned cnt[128]; for (int i = 0; i < 128; ++i) { cnt[i] = 0; } 或者 memset(cnt, 0, sizeof(cnt)); 98、如何使用map 以及map下标和vector如何联系起来使用 map<char, int> mapdata; void Insert(char ch) { dec.push_back(ch); mapdata[ch]++; } for (it = dec.begin(); it!= dec.end(); it++) { if (mapdata[*it] == 1) { return *it; } } 另一种方法:如何单独使用循环条件,遍历map map<char, int>resMap; resMap.find(ch) != resMap.end() find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器 99、 始终记住,char类型是属于整型类的 如何利用string 和ch来表示数组的下标 string s; void Insert(char ch) { s += ch;---注意此方法,有效。为了使用其下标 occurrence[ch]+=1; } int len = s.size(); for (int i = 0; i < len; ++i) { if (occurrence[s[i]] == 1) { return s[i]; } } 100、当使用哈希表,key为char类型,value为int类型,则必须要记住用一个string类型或者vector<int>或者vector<char>来记录它的字符串,以便使用map[value] = key; 101、如何查看一个链表中是否存在环,就是找两个指针,一前一后,快指针比慢指针快走1步,如果相遇,则表示有环存在。 102、int value = pNode->val; ListNode* pToBeDel = pNode; //将相同值的结点循环删除,直至下一个结点的val不等于value //这个循环条件的思路好处,在于第一次判断的时候,自己和自己相等,因为已经确定该结点要被删除 while(pToBeDel != NULL && pToBeDel->val == value) { pNext = pNode->next; delete pToBeDel; pToBeDel = NULL; pToBeDel = pNext; } 103、利用奇数和偶数来做判断选择分支;思想很重要。 判断它是奇数偶数 int current = 0; int next = 1; if (levels[current].empty()) { current = 1-current; next = 1-next; } 104、在删除弹出一个结点之前,一定要记的先备份结点 TreeNode* pNode = levels[current].top(); levels[current].pop(); 105、记住在队列中,求 头结点操作---front(), 尾结点---back(); 106、string :: push_back 原型:void push_back(char c); 说明:添加字符到字符串的末尾。 std :: string :: append 原型:string&append(const string&str); 说明:把字符串型字符串海峡连接到源字符串结尾。 原型:string&append(const string&str,size_t subpos,size_t sublen = npos); 说明:用字符串型字符串STR中从下标为SUBPOS处开始的sublen长度的字符串连接到当前字符串结尾。 原型:string&append(const char * s); 说明:把字符型字符串小号连接到当前字符串结尾。 原型:string&append(const char * s,size_t n); 说明:用炭型字符串小号开始的Ñ个字符连接到当前字符串结尾。 原型:string&append(size_t n,char c); 说明:在当前字符串结尾添加ň个字符℃。 原型:template <class InputIterator> string&append(InputIterator first,InputIterator last); 说明:以相同的顺序在[first,last]范围内追加字符序列的副本。 原型:string&append(initializer_list il); 说明:按照相同的顺序在il中追加每个字符的副本。 std :: string :: operator + = 原型:string&operator + =(const string&str); 说明:把字符串型字符串海峡连接到源字符串的结尾。 原型:string&operator + =(const char * s); 说明:把字符型字符串小号连接到源字符串的结尾。 原型:string&operator + =(char c); 说明:把字符ç连接到源字符串的结尾。 原型:string&operator + =(initializer_list il); 107、原型声明:char *strcpy(char* dest, const char *src); 头文件:#include <string.h> 和 #include <stdio.h> 功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。 108、如何将一个string类型赋值给一个char*类型 首先将string类型通过string.c_str()转化为char*类型。 然后利用strcpy(char*, char*)进行拷贝,拷贝前记得要对目的地址指向的内存进行容量的预定。 连接两个char*指向的字符串,应该用strcat(char*, char*) 109、如何将char*指向的字符,变成整数 char *str num = num*10 + (*str - '0'); 110、关于动态数组进行初始化操作问题 对于内置数据类型元素的数组,必须使用()来显示指定程序执行初始化操作,否则程序不执行初始化操作: int *pia = new int[10]; // 每个元素都没有初始化 int *pia2 = new int[10] (); // 每个元素初始化为0 类类型元素的数组,则无论是否使用(),都会自动调用其默认构造函数来初始化: string *psa = new string[10]; // 每个元素调用默认构造函数初始化 string *psa = new string[10](); // 每个元素调用默认构造函数初始化 111、关于新建树结点的初始化操作 TreeNode* root = new TreeNode(num); 或者 TreeNode* root = new TreeNode(); root->val = num; root->left = NULL; root->right = NULL; 112、可以传递一个指针的引用; char *&p是一个指向字符指针的引用。 在参数中传递时,如果需要修改指针本身,一般用来替换 char **。 char ** 有二义(举例略) TreeNode* decode(char *&str) { if(*str=='#') { str++; return NULL; } } TreeNode* Deserialize(char *str) return decode(str); 113、判断一个数据是奇数还是偶数,不要用取余来处理。 而是要用与1相与运算来处理。 114、 //定义一个布尔值矩阵,用来标识路径是否已经进入每个格子。默认初始化值为false bool *isOk=new bool[rows*cols](); isOk[curx*cols+cury] bool* flag=new bool[rows*cols]; 上述定义两者区别:前者是定义了多个对象,且调用的是无参构造函数; 后者也是定义了多个对象,它的默认是调用无参的构造函数 bool* flag=new bool[rows*cols](1); 定义了多个对象,它的默认是调用有参的构造函数,进行初始化 115、如何将一个数,从个位依次相加到最高位 比如:115,1+1+5 =7 int sum=0; while(number>0) { sum+=number%10; number/=10; } 116、 对于字符串去重操作 利用bool类型进行判断 bool table[] = {false}; if (table[c-'a'] == false) { pOutout[k++] = c; table[c-'a'] = true; } 117、 将任意类型的数字转换为字符串 char*itoa(int value,char*string,int radix);int value 被转换的整数,char *string 转换后储存的字符数组 |
* This source code was highlighted by YcdoiT. ( style: Borland )