01 二维数组
bool Find(int* matrix, int rows, int columns, int number)
// 这里传入数组 (int*)matrix 或 &matrix[0][0]
{
bool found = false;
// 确保数组不为空,nullptr!!C++定义的空指针
if (matrix != nullptr && rows > 0 && columns > 0)
{
// 从右上角开始搜索,初始化行、列
int row = 0;
int column = columns - 1;//
while (row < rows && column >= 0)
{
// 步骤 1:右上角数字为所寻找的数字
if (matrix[row * columns + column] == number)
{
cout<< matrix[row * columns + column]<<endl;
found = true;//标识为true
break;
}
// 步骤 2:右上角数字大于所寻找数字,可以排除右上角数字所在的列
//因为列下面都是比该数字大的数字
else if (matrix[row * columns + column] > number)
--column;
// 步骤 3:右上角数字大于所寻找数字,可以排除右上角数字所在的行
//因为该数字左侧,即行所在数字都是比该数字小的数字
else
++row;
}
}
return found;//找到,found=true;否则为false。
}
//从左下角比较
bool Find(int target, vector<vector<int>> array) {
int rows = array.size();
int cols = array[0].size();
bool isFound = false;
if(rows > 0 && cols > 0)
{
int row = rows-1, col = 0;
while(row>=0&&col<cols)
{
int cmp = array[row][col];
if(cmp == target)
{
isFound=true;
cout<<"target position: row "<<row<<",column "<<col<<endl;
break;
}
else if(cmp>target)
{
--row;
}
else
{
++col;
}
}
}
return isFound;
}
字符串
会把常量字符串放到单独的一个内存区域中,当几个指针赋值给相同的常量字符串时,它们实际上会指向相同的内存地址
但如果用常量内存初始化数组,数组的地址是不相同的。
02 替换空格
#include<iostream>
using namespace std;
// 替换空格,length是字符数组string的总容量
void ReplaceBlank(char string[], int length){
if (string == NULL || length <= 0){
return;
}
// 字符串string的实际长度
int originLength = 0;
int numberOfBlank = 0;
int i = 0;
// 统计空格的数量和字符的数量
while (string[i] != '\0'){
++originLength;//统计字符的数量
if (string[i] == ' ')
++numberOfBlank;//统计空格数量
++i;
}
// 替换空格后的字符串新长度——一个空格用%20代替,增加了两个长度
int newLength = originLength + numberOfBlank * 2;
if (newLength > length)
return;
/*替换空格操作!!
——两个指针,一个指向原始字符串的结尾,一个在新的字符串的结尾位置
*/
int indexOfOriginal = originLength;//原始字符串长度
int indexOfNew = newLength;//新的字符串长度
while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal){
if (string[indexOfOriginal] == ' '){
string[indexOfNew--] = '0';
string[indexOfNew--] = '2';
string[indexOfNew--] = '%';
}
else{
string[indexOfNew--] = string[indexOfOriginal];
}
indexOfOriginal--;
}
}
// 测试
int main(void){
char str[10] = " hello";
char str2[10] = "he llo";
char str3[10] = "hello ";
char str4[30] = "We are happy.";
char str5[30] = "helloWorld.";
char *str6 = NULL;
char str7[10] = "";
char str8[10] = " ";
char str9[20] = " ";
// 空格位于字符串的最前面
cout << "origin: " << str;
ReplaceBlank(str, 10);
cout << ",--> " << str << endl;
// 空格位于字符串的最后面
cout << "origin: " << str2;
ReplaceBlank(str2, 10);
cout << ",--> " << str2 << endl;
// 空格位于字符串的中间
cout << "origin: " << str3;
ReplaceBlank(str3, 10);
cout << ",--> " << str3 << endl;
// 字符串中有多个连续空格
cout << "origin: " << str4;
ReplaceBlank(str4, 30);
cout << ",--> " << str4 << endl;
// 输入的字符串没有空格
cout << "origin: " << str5;
ReplaceBlank(str5, 30);
cout << ",--> " << str5 << endl;
// 字符串是空指针
ReplaceBlank(str6, 10);
// 字符串是空字符串
cout << "origin: " << str7;
ReplaceBlank(str7, 10);
cout << ",--> " << str7 << endl;
// 字符串只有一个空格字符
cout << "origin: " << str8;
ReplaceBlank(str8, 10);
cout << ",--> " << str8 << endl;
// 字符串中只有多个连续空格
cout << "origin: " << str9;
ReplaceBlank(str9, 20);
cout << ",--> " << str9 << endl;
system("pause");
return 0;
}
链表
链表的简单使用
假设我们要构造一个int类型的链表,那么一个节点中就需要包含两个元素:
1.一个是当前节点所保存的值,设为int value。
2.另一个就是 指向下一个节点的指针,我们再假设这个节点类是node,那么这个指针就是 node *next。
这里一定不是int *next。因为这个指针指向的下一个元素是一个类的实例,而不是int类型的数据。那么node这个类最简单的实现就如下
struct ListNode{
int value;
ListNode *next;
}
在链表末尾添加一个结点代码:
void AddToTail(ListNode **pHead,int value){
//pHead是一个指向指针的指针
ListNode *pNew=new ListNode();
pNew->value=value;
pNew->next=nullptr;//生成一个新的结点
if(*pHead==nullptr){//若为最后一个结点,则直接添加
*pHead=pNew;
} else{
ListNode* pNode = *pHead;//再创造一个指针
while(pNode->next != nullptr)
//只要该指针的next!=null,指针指向下一个结点
pNode = pNode->next;
pNode->next = pNew;//当指针next=null,则将生成的结点加入
}
return;
}
// 删除某个值为value的结点
void RemoveNode(ListNode** pHead, int value){
if(pHead == nullptr || *pHead == nullptr) return;
ListNode* pToDeleted = nullptr;
if((*pHead)->val == value){
pToDeleted = *pHead;
*pHead = (*pHead)->next;
}else{
ListNode* pNode = *pHead;
while(pNode->next != nullptr && pNode->next->val != value)
pNode = pNode->next;
if(pNode->next != nullptr && pNode->next->val == value){
pToDeleted = pNode->next;
pNode->next = pNode->next->next;
}
}
if(pToDeleted != nullptr){
delete pToDeleted;
pToDeleted = nullptr;
}
return;
}
反向打印链表
struct ListNode {
int val;
ListNode *next;
ListNode(int x) :val(x), next(NULL) {}
};
class Solution {
public:
ListNode* ReverseList(ListNode* p1) {
ListNode* p2 = nullptr; // p2为反转链表,初始化为nullptr
ListNode* pNext = nullptr; // pNext为每次抛弃表头的p1指针
while(p1){// 当p1指针不为空时
pNext = p1->next;// pNext存放当前结点的下一结点的地址
p1->next = p2; // 当前结点指向前一个结点——将p1结点给p2
p2 = p1; // p2往前走一个结点
p1 = pNext; // p1 也走到下一个结点
}
return node;
}
};
树
重建二叉树
#include <iostream>
#include <vector>
using namespace std;
// 结构体定义树的类型
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
//允许我们用 TreeNode node(int x)的方式把val赋值为x,left,right为NULL。
};
// 返回类型为树的指针,指针指向这棵树
// 输入参数为前序遍历和中序遍历的结果,类型为vector<int>的数组
//声明一个int向量以替代一维的数组:vector <int> a;(等于声明了一个int数组a[],大小没有指定,可以动态的向里面添加删除)。
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin){
// 若遍历结果均为空 结束递归
if(pre.size() == 0 || vin.size() == 0){
return nullptr;
}
// 用根节点去初始化这棵树
TreeNode *tree = new TreeNode(pre[0]);
// 仅仅声明并初始化根节点
int root = 0;
int size = pre.size();
// root记录了根节点在中序遍历结果中的下标
for(int i = 0; i < size; i++){
if(vin[i] == pre[0]){
root = i;
}
}
// 定义左右子树的前序遍历结果和中序遍历结果
vector<int> pre_left, pre_right, vin_left, vin_right;
// 依据规则填空
/*push_back()函数的用法
函数将一个新的元素加到vector的最后面,位置为当前最后一个元素的下一个元素
*/
for(int i = 0; i < root; i++){//对两个遍历序列,添加左子树
pre_left.push_back(pre[i+1]);
vin_left.push_back(vin[i]);
}
// 依据规则填空
for(int i = root + 1; i < size; i++){
pre_right.push_back(pre[i]);
vin_right.push_back(vin[i]);
}
// 递归的对左子树和右子树进行重建操作(输入他们各自对应的前序遍历结果和中序遍历结果即可)
tree->left = reConstructBinaryTree(pre_left, vin_left);
tree->right = reConstructBinaryTree(pre_right, vin_right);
// 最终 返回指向该树的指针
return tree;
}
int main() {
// n为树的节点总数
int n;
cin >> n;
vector<int> pre(n); // 声明前序遍历结果
vector<int> vin(n); // 声明中序遍历结果
for(int i = 0; i < n; i++) // 输入前序遍历结果
cin >> pre[i];
for(int i = 0; i < n; i++)// 输入中序遍历结果
cin >> vin[i];
// 重建二叉树
TreeNode* myTree = reConstructBinaryTree(pre, vin);
return 0;
}
java代码实现(较易)
import java.util.Arrays;
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre.length==0)
return null;
TreeNode tree=new TreeNode(pre[0]);
for(int i=0;i<in.length;i++)
{
if(in[i]==pre[0])
{
tree.left=reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
tree.right=reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(in,i+1,in.length));
}
}
return tree;
栈和队列
用两个栈实现一个队列
插入一个元素:直接将元素插入stack1即可;
删除一个元素:当stack2不为空时 ,直接弹出栈顶元素,当stack2为空时,将stack1元素逐个弹出并压入stack2,然后在弹出栈顶元素;
class Solution
{
private:
stack<int> stack1;
stack<int> stack2;
public:
void push(int node) {
stack1.push(node);
}
int pop() {
int x;
if (stack2.empty())//stack2为空时,将stack1元素逐个弹出并压入stack2,然后在弹出stack2的栈顶元素
{
while (!stack1.empty())
{
stack2.push(stack1.top());//数字进入stack
stack1.pop();//将数字弹出
}
x = stack2.top();//用x保存数字
stack2.pop();//数字弹出
}
else //stack2不为空时,直接弹出stack2的栈顶元素
{
x = stack2.top();
stack2.pop();
}
return x;
}
};
用两个队列实现一个栈
**两个队列的实现 仅在pop时处理
1、pop时,最后一个元素之前的元素全部出队,放到临时队列
2、pop最后一个元素
3、再将临时队列中的元素全部移回来
class MyStack {
private:
queue<int> queue1;
queue<int> queue2;
public:
/** Initialize your data structure here. */
MyStack() {}
/** Push element x onto stack. */
void push(int x) {
queue1.push(x);//插入队列
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
while(queue1.size()>1){//将前size-1个元素移至中转队列
queue2.push(queue1.front());
queue1.pop();
}
int a=queue1.front();//保存队列数字
queue1.pop();//pop操作!!!
while(!queue2.empty()){//再将中转队列中的所有元素移回队列
queue1.push(queue2.front());
queue2.pop();
}
return a;
}
/** Get the top element. */
int top() {
return queue1.back();
}
/** Returns whether the stack is empty. */
bool empty() {
return queue1.empty();
}
};