面经准备:剑指offer 刷题 代码及笔记 C/C++ 版

#include<iostream>
#include<string>
#include<fstream>
#include<vector>
#include<algorithm>
#include<stack>
using namespace std;

//1.数组
//2.链表
//
class ListNode{  
public:  
	int val;
    ListNode *next;
	ListNode(int x){
		val = x;
		next = NULL;
	}
    ListNode(){  
        next = NULL;    //显式构造函数,每次对新声明的链表类进行初始化,即表示  
                        //创建一个新的"空"链表,链表中只有头指针,并且头指针的值为NULL,表示头指针  
                        //指向的部分也无任何数据元素  
    }  
    void Insert(ListNode *head,ListNode *node,int position);  
    void Output(ListNode *head);  
};  
void ListNode::Insert(ListNode *head,ListNode *node,int position){     //position表示要插入的位置  
            if(head==NULL){              //在头指针为空指针的情况下,链表是空的,无任何数据元素  
                                        //包括头结点在内.因此呢,我们在插入节点的时候,如果发现头结点为空指针  
                head = node;             //的情况,那么这就意味着我们插入的这个节点要将其设置为头结点,  
                return;                 //而后一一插入的节点则接在该节点的后方,并且通过这个节点从头开始遍历  
                                        //能够遍历到链表中所有的数据元素  
  
  
            }  
            if(position==0){      //插入的是第0个位置,为了方便,我们暂且规定头结点为第0个节点  
                                  //那么如果插入的是第0个位置的话,说明插入的节点要成为新的头结点  
                                  //而不管之前有没有头结点  
            node -> next = head;  
            head = node;          //完成头结点的更新,表示头结点现在是node节点  
            return;  
  
            }  
            ListNode *current_node = head;     //从头结点开始遍历插入的位置  
            int i = 0;                    //表示已经遍历过的节点数目  
            while(current_node -> next != NULL && i < position-1){  
                                                                //不断寻找要插入的位置的前一个位置,然后插入在这个位置的节点与下一个位置的节点之间  
                current_node = current_node -> next;            //不断更新current_node的值  
                i++;  
            }  
            if(i == position-1){            //找到了插入的位置,先更新插入节点的指针域,记录当前遍历到的位置的下一个节点  
                                            //然后再接上前面的节点  
  
                node -> next = current_node -> next;  
                current_node -> next = node;  
            }  
}  
void ListNode::Output(ListNode *head){  
            if(head==NULL){  
                return;       //链表为空链表,无任何数据元素可输出  
            }  
            ListNode *current_node = head;     //从头结点开始遍历  
            while(current_node!=NULL){  
                cout << current_node -> val << " ";  
                current_node = current_node -> next;  
            }  
            cout << endl;  
} 
//
//
//
//第1.1题
bool duplicate_11(int numbers[], int length, int* duplication) {	
	int *copy = new int[length]();//copy一一对应
	int count=0;//dup计数器
        for(int i=0;i<length;i++){
            if(copy[numbers[i]]==-1){
				duplication[count++] = numbers[i];
				cout<<duplication[0];
                return true;
            }
            else copy[numbers[i]]=-1;
        }
        return false;
    }

//第1.2题
int replace_12(const vector<int>& A,int pos){
	vector<int> B(A);
	//for (int i = 0; i < B.size(); i++) {
    //cout << B.at(i) << endl;
	//}
	B.at(pos)=1;
	int mut=1;
	for(int i=0;i<A.size();i++){
		mut=mut*B[i];
	}
	return mut;
}
 vector<int> multiply_12(const vector<int>& A) {
    //B是A中元素连乘,去掉i
    //给一个A的引用
	 vector<int> B;
	 cout<<A.size();
	 int len = A.size();
	 for (int i =0;i<len;i++){
		 B.push_back(replace_12(A,i));
		 cout<<B.back()<<endl;
	 }
	 return B;
    }

//第1.3题
//在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
  bool find_13(int target, vector<vector<int> > array) {
		int row=array.size();
		int col=array[0].size();
		//从左下角找
		int i=row-1,j=0;
		while(i>0&&j<col){
			if(target==array[i][j]){
				return true;
			}
			else if(target>array[i][j]){
				j++;continue;
			}
			else{
				i++;continue;
			}
		}
		return false;
    }
  
  //第2.1题
  //一个链表中包含环,请找出该链表的环的入口结点。//用例中的入口应该是2
    ListNode* EntryNodeOfLoop_21(ListNode* pHead)
    {
        //遍历的过程中标记遇到的节点
		//记录上一个
		//断链法
		if(pHead==NULL||pHead->next==NULL) return NULL;
		ListNode *pri=pHead;
        ListNode *cur=pHead->next;
		//ListNode pri;
		while(cur!=NULL){
			cout<<pri->val;
			pri->next=NULL;
			pri = cur;
			cur=cur->next;			
			}						
		return pri;
    }
ListNode* EntryNodeOfLoop_211(ListNode* pHead){
        //快指针,慢指针相遇法
		//快每次走2,慢走1,相遇时候是环的长度
		//然后fast从头走再次相遇时,就是入口
//第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。
//第二步,找环的入口。接上步,当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口。
 if(pHead == NULL || pHead->next == NULL)
            return NULL;
        ListNode *p1 = pHead;
        ListNode *p2 = pHead;
        while(p2 != NULL && p2->next != NULL ){
            p1 = p1->next;
            p2 = p2->next->next;
            if(p1 == p2){
                p2 = pHead;
                while(p1 != p2){
                    p1 = p1->next;
                    p2 = p2->next;
                }
                if(p1 == p2)
                return p1;
            }
        }
        return NULL;
    }

//第2.2题
//在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
    ListNode* deleteDuplication(ListNode* pHead)
    {
		排序的...则连续分布
		每次读取一个判断跟后面的值是否相同,相同就标记,直到遇到不用的,则这一段是要删除的
		//if(pHead==NULL||pHead->next==NULL){
		//	return pHead;
		//}
		//if(pHead->next->next==NULL){
		//	if(pHead->val==pHead->next->val){
		//		return NULL;
		//	}
		//	else{
		//		return pHead;			
		//	}
		//}
		//ListNode *del;//删除的起点
		//ListNode *cur=pHead;//后锋军 //前探是cur->next和cur->next->next
		//while(cur->next->next!=NULL){
		//	if(cur->next->val==cur->next->next->val){
		//		//如果前探和前前探相同,则下一个为删除的起点
		//		del=cur;//cur后面的点都不要了,相同值是del->next->val
		//		cur=cur->next->next;//cur移动到后面
		//		while(del->next->val==cur->next->val){//只要和cur->next的值相同 都是要删的
		//			cur=cur->next;
		//		}
		//		//直到不一样的时候,此时cur不同于del
		//		del->next=cur->next;//把里面的点直接释放掉//cur有可能是下一串的起点
		//	}
		//}
		处理最后两个
		
		
		
		//按照删除的思路太繁琐,逆向思考,删除变成新建,不重复的节点重新连成一个表
        if (pHead == NULL || pHead->next == NULL) { // 只有0个或1个结点,则返回
            return pHead;
        }
        if (pHead->val == pHead->next->val) { // 当前结点是重复结点
            ListNode *pNode = pHead->next;
            while (pNode != NULL && pNode->val == pHead->val) {
                // 跳过值与当前结点相同的全部结点,找到第一个与当前结点不同的结点
                pNode = pNode->next;
            }
            return deleteDuplication(pNode); // 从第一个与当前结点不同的结点开始递归
        } else { // 当前结点不是重复结点
            pHead->next = deleteDuplication(pHead->next); // 保留当前结点,从下一个结点开始递归
            return pHead;
        }
    }
//第2.3题
//输入一个链表,从尾到头打印链表每个节点的值。
vector<int> printListFromTailToHead(ListNode* head) {
    vector<int> result;
    ListNode *i=head;
    stack<int> sta;
    while(i!=NULL){
        sta.push(i->val);
        i=i->next;
    }
    while(!sta.empty()){
        //cout<<sta.pop();
        result.push_back(sta.top());
        sta.pop();
    }
    return result;
}

//第3.1题 700ms 太长了
//大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。n<=39 F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)
    int Fibonacci_1(int n) {
		//F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)
		//递归
		if(n<0) return 0;
		if(n==0||n==1) return 1;
		else {

			return Fibonacci_1(n-1)+Fibonacci_1(n-2);
		}
    }
	//用动态规划来做 5ms
     int Fibonacci(int n) {

        int f = 0, g = 1;
		//每次计算只于前两个有关 减少代价
        while(n>0) {
			n--;
            g= g+f;
            f= g-f;
			//首先判断有几个值,f表示当前值f(n),g表示下一个值f(n+1),则第一次循环g表示f(n+2),f-g后f表示f(n+1) 左脚踩右脚上天法。至于n只表示是第几个数,只要够减就行
        }
        return f;
    }
	//第3.2题
	// 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
	int jumpFloor_1(int number) {//529ms
		//跳n介,有几种跳法,x=1或x=2 排列组合
		//可以用递归或者动态规划来做
		//递归法
		//int x=0;
		if(number==0) return 0;
		else if(number==1) return 1;
		else if(number==2) return 2;//两种跳法
		else{
			return jumpFloor_1(number-1)+jumpFloor_1(number-2);//拆解的时候自带了加的数字
		}

    }
		int jumpFloor(int number) {
		//跳n介,有几种跳法,x=1或x=2 排列组合
		//可以用递归或者动态规划来做
		//动态规划法 左脚踩右脚法
		//f(0)=0;f(1)=1;
		if(number<=0) return 0;
		if(number==1||number==2) return number;
		int f=1,g=2;//
		while(number>2)//number循环的起始处要小心
		{
			number--;
			g=g+f;//先根据f(n)和f(n+1)得到f(n+2)
			f=g-f;//再根据f(n+2)和f(n)得到f(n+1) 完成一次迭代
		}
		return g;
		}

//第3.3题
	int jumpFloorII(int number) {
        //变态死青蛙
		//每次能跳1-n介 化简出通项f(n)=2*f(n-1)
		if(number==0) return 0;
		else if(number ==1) return 1;
		else 
		return jumpFloorII(number-1)*2;

    }
	//第3.4题
	//我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
	int rectCover_1(int number) {
		//递归法
		//f0=0,f1=1,f2=2,f3=3...斐波那契
		//fn=f(n-1)+f(n-2)//n-1表示顺着放,n-2表示占位置的放

	if(number<=0) return 0;
	else if(number==1||number==2) return number;
	else 
		return rectCover_1(number-1)+rectCover_1(number-2);
		
    }

	int rectCover(int number) {
	//动态规划法
	//f0=0,f1=1,f2=2,f3=3...斐波那契
	//fn=f(n-1)+f(n-2)//n-1表示顺着放,n-2表示占位置的放
	if(number<=0) return 0;
	else if(number==1||number==2) return number;
	int f=1,g=2;
	while (number>2){
		number--;
		g=g+f;
		f=g-f;
	}
	return g;
    }

	//第四题
	//将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
	//字符'0'到'9'的ascii值的低4个二进制位刚好就是0到9所以str[i]&0xf等于str[i]-'0'。 位运算会比乘法运算效率高那么一点点点点...
	int StrToInt(string str) {
        //跟位置有关
		//单个char转为int
		//非法检测
        if(str.empty())
            return 0;
        int symbol = 1;//默认符号为正
        if(str[0] == '-'){//处理负号
            symbol = -1;
            str[0] = '0'; //这里是‘0’ 不是0
        }else if(str[0] == '+'){//处理正号
            symbol = 1;
            str[0] = '0';
        }
        int sum = 0;
        for(int i=0;i<str.size();++i){
            if(str[i] < '0' || str[i] > '9'){
                sum = 0;//只要有非法符号,则sum为0 最后返回值为0
                break;
            }
              
            sum = sum *10 + str[i] - '0';//str[i]里面是数字的ascii码 可以直接计算的 //从低位开始 每次sum翻10倍计算
             
        }
        return symbol * sum;//最后计算符号
    }

	//5.1
	//请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
	bool match(char* str, char* pattern)
	{
		//用递归的思想


    }
	//5.2
	//请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
	bool isNumeric(char* string)
    {
        //枚举首先考虑有哪些情况

    }

	//5.3
   //Insert one char from stringstream
    void Insert(char ch)
    {
         
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
																																																																																											
    }

 int main() {
	 //测试用例们~~
	//第1.1题
	//int n[7]={1,2,3,4,4,6,7};
	//int dup[7];
	//duplicate_11(n,7,dup);


	//第1.2题
	//int n[7]={1,2,3,4,5,6,7};
	//vector<int> vec(n,n+7);
	//multiply_12(vec);
	
	//第1.3题
	 //int mux[3][3]={{1,2,3},{2,3,4},{3,4,5}};
	 //for(int i =0;i<3;i++){
		// for(int j=0;j<3;j++){
		//	cout<<mux[i][j];
		// }
		// cout<<endl;
	 //}
	 //vector<vector<int>> vec;
	 //vector<int> vec0(mux[0],mux[0]+3);
	 //vector<int> vec1(mux[1],mux[1]+3);
	 //vector<int> vec2(mux[2],mux[2]+3);
	 //vec.push_back(vec0);
	 //vec.push_back(vec1);
	 //vec.push_back(vec2);
	 //for(int i =0;i<3;i++){
		// for(int j=0;j<3;j++){
		//	cout<<vec[i][j];
		// }
		// cout<<endl;
	 //}
	 //cout<<find_13(5,vec);
	 
	 //第2.1题
	//ListNode *a = new ListNode(1);
	//ListNode *b = new ListNode(2);
	//ListNode *c = new ListNode(3);
	//ListNode *d = new ListNode(4);
	//ListNode listhead;//没什么意义的,为了调用
	//listhead.Insert(a,b,1);
	//listhead.Insert(a,c,2);
	//listhead.Insert(a,d,3);
	//d->next = b;
	listhead.Output(a);
	//cout<<"aa"<<EntryNodeOfLoop_211(a)->val;

	 //第2.2题
	//ListNode *a = new ListNode(1);
	//ListNode *b = new ListNode(2);
	//ListNode *c = new ListNode(3);
	//ListNode *d = new ListNode(3);
	//ListNode *e = new ListNode(4);
	//ListNode *f = new ListNode(4);
	//ListNode *g = new ListNode(5);
	//ListNode listhead;//没什么意义的,为了调用
	//listhead.Insert(a,b,1);
	//listhead.Insert(a,c,2);
	//listhead.Insert(a,d,3);
	//listhead.Insert(a,e,4);
	//listhead.Insert(a,f,5);
	//listhead.Insert(a,g,6);
	//listhead.Output(deleteDuplication(a));

	 //第2.3题
	//ListNode *a = new ListNode(1);
	//ListNode *b = new ListNode(2);
	//ListNode *c = new ListNode(3);
	//ListNode *d = new ListNode(4);
	//ListNode listhead;//没什么意义的,为了调用
	//listhead.Insert(a,b,1);
	//listhead.Insert(a,c,2);
	//listhead.Insert(a,d,3);
	//vector<int> re = printListFromTailToHead(a);
	//for(int i=0;i<re.size();i++){
	//	//cout<<re.size();
	//	cout<<re[i];
	//}

	//第3.1题
	// cout<<Fibonacci(6);

	//第3.2题
	//cout<<jumpFloor(5);

	//第3.3题
	//cout<<jumpFloorII(3);

	//第3.4题
//	cout<<rectCover(3);

	//第4题
	//string a="123456";
	//string b="12a3";
	//cout<<StrToInt(a)<<endl;
	//cout<<StrToInt(b)<<endl;

	//5.1
	 //char str[3]={'a','a','a'};
	 //char pat[3]={'a','.','a'};
	 //cout<<match(str,pat);
	
	//5.2

	//5.3

	cout<<endl;
	system("pause");
	return 0;
    
}`																			


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值