剑指offer第七章&第八章

剑指offer第七章&第八章

1.把字符串转换成整数
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
分析:思路在代码里已经体现
 1 class Solution {
 2 public:
 3     int StrToInt(string str) 
 4     {
 5       if(str.empty())
 6             return 0;
 7         int symbol = 1;//正负号初始化为1表示正数
 8         if(str[0] == '-')
 9         {//处理负号
10             symbol = -1;//表示是负数
11             str[0] = '0'; //这里是‘0’ 不是0
12         }
13         else if(str[0] == '+')
14         {//处理正号
15             symbol = 1;//表示是正数
16             str[0] = '0';
17         }
18         int sum = 0;
19         for(int i=0;i<str.size();++i)
20         {
21             if(str[i] < '0' || str[i] > '9')
22             {
23                 sum = 0;
24                 break;
25             }
26             sum = sum *10 + str[i] - '0';
27         }
28         return symbol * sum;//正负号乘以sum,即表示字符串所表示的整数
29     }
30 };

2..数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 
例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
分析:注意到数组中的数字都在0——n-1的范围内。如果没有重复数字,那么排序之后数字i将出现在下标为i的位置
从头到尾依次扫描这个数组中的每个数字。当扫描到下标为i的数字时,首先比较这个数字(m)是不是等于i。如果是,接着扫描下一个数字。如果不是,再拿m和第m个数字比较。如果相等,就找到了一个重复数字。如果不等,就把第i个数字和第m个数字交换,把m放到属于它的位置。接下来重复比较,直到找到重复数字。
 1 class Solution {
 2 public:
 3     // Parameters:
 4     //        numbers:    an array of integers
 5     //        length:      the length of array numbers
 6     //        duplication: (Output) the duplicated number in the array number
 7     // Return value:      true if the input is valid, and there are some duplications in the array number
 8     //                    otherwise false
 9     bool duplicate(int numbers[], int length, int* duplication) 
10     {
11         if(numbers==NULL||length<=0)
12             return false;
13         for(int i=0;i<length;++i)
14         {
15             if(numbers[i]<0||numbers[i]>length-1)
16                 return false;
17         }
18         for(int i=0;i<length;++i)
19         {
20             while(numbers[i]!=i)
21             {
22                 if(numbers[i]==numbers[numbers[i]])
23                 {
24                     *duplication=numbers[i];
25                     return true;
26                 }
27                 int temp=numbers[i];
28                 numbers[i]=numbers[temp];
29                 numbers[temp]=temp;
30             }
31         }
32         return false;
33     }
34 };

3.构建乘积数组

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
分析:
B[i]的值可以看作下图的矩阵中每行的乘积。 
下三角用连乘可以很容求得,上三角,从下向上也是连乘。 
因此我们的思路就很清晰了,先算下三角中的连乘,即我们先算出B[i]中的一部分,然后倒过来按上三角中的分布规律,把另一部分也乘进去。 
 
 1 class Solution {
 2 public:
 3     vector<int> multiply(const vector<int>& A)
 4     {
 5         int n=A.size();
 6         vector<int> B(n);
 7         B[0]=1;
 8         for(int i=1;i<n;++i)
 9         {
10             B[i]=B[i-1]*A[i-1];
11         }
12         double temp=1;
13         for(int i=n-2;i>=0;--i)
14         {
15             temp*=A[i+1];
16             B[i]*=temp;
17         }
18         return B;
19     }
20 };

 4.表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
分析:在代码里体现
 1 class Solution {
 2 public:
 3     bool isNumeric(char* string)
 4     {
 5         if(string==NULL)
 6             return false;
 7         if(*string=='+'||*string=='-')//首先判断第一个字符是不是正负号
 8             ++string;
 9         if(*string=='\0')//边界判断
10             return false;
11         bool numeric=true;
12         scanDigits(&string);//扫描数位
13         if(*string!='\0')
14         {
15             if(*string=='.')//小数
16             {
17                 ++string;
18                 scanDigits(&string);
19                 if(*string=='e'||*string=='E')//科学记数法
20                     numeric=isExp(&string);
21             }
22             //整数
23             else if(*string=='e'||*string=='E')
24                 numeric=isExp(&string);
25             else
26                 numeric=false;
27         }
28         return numeric&&*string=='\0';
29     }
30     void scanDigits(char** string)//扫描字符串中0到9的数位
31     {
32         while(**string !='\0'&&**string>='0'&&**string<='9')
33             ++(*string);
34     }
35     bool isExp(char** string)//用来匹配用科学记数法表示数值的结尾部分,结尾部分的第一个字符是‘e’或者‘E’,接下来可能有一个正负号
36     {
37         if(**string!='e'&&**string!='E')
38             return false;
39         ++(*string);
40         if(**string=='+'||**string=='-')
41             ++(*string);
42         if(**string=='\0')
43             return false;
44         scanDigits(string);
45         return (**string=='\0') ? true:false;
46     }
47 };

 5.字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。
例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。
当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述::如果当前字符流没有存在出现一次的字符,返回#字符。
分析:
 1 class Solution
 2 {
 3 public:
 4     string s;
 5     char hash[256]={0};
 6   //Insert one char from stringstream
 7     void Insert(char ch)
 8     {
 9         s+=ch;
10         hash[ch]++;
11     }
12   //return the first appearence once char in current stringstream
13     char FirstAppearingOnce()
14     {
15         int size=s.size();
16         for(int i=0;i<size;++i)
17         {
18             if(hash[s[i]]==1)
19                 return s[i];
20         }
21         return '#';
22     }
23 };

 6.链表中环的入口结点

一个链表中包含环,请找出该链表的环的入口结点。
 
 1 /*
 2 struct ListNode {
 3     int val;
 4     struct ListNode *next;
 5     ListNode(int x) :
 6         val(x), next(NULL) {
 7     }
 8 };
 9 */
10 class Solution {
11 public:
12     //在链表中存在环的前提下找到一快一慢两个指针相遇的结点,一定在环内
13     ListNode* MeetingNode(ListNode* pHead)
14     {
15         if(pHead==NULL)
16             return NULL;
17         ListNode* pSlow=pHead->next;
18         if(pSlow==NULL)
19             return NULL;
20         ListNode* pFast=pSlow->next;
21         while(pFast!=NULL&&pSlow!=NULL)
22         {
23             if(pFast==pSlow)
24                 return pFast;
25             pSlow=pSlow->next;
26             pFast=pFast->next;
27             if(pFast!=NULL)
28                 pFast=pFast->next;
29         }
30         return NULL;
31     }
32     //找到环中任意一个结点之后,就能得出环中结点的数目,并找到环的入口结点
33     ListNode* EntryNodeOfLoop(ListNode* pHead)
34     {
35         ListNode* meetingNode=MeetingNode(pHead);
36         if(meetingNode==NULL)//没有环
37             return NULL;
38         //计算环中结点数
39         int nodesInLoop=1;
40         ListNode* pNode1=meetingNode;
41         //从相遇的结点开始,一边继续向前移动一边计数,当再次回到这个结点,就统计出了环中节点数
42         while(pNode1->next!=meetingNode)
43         {
44             pNode1=pNode1->next;
45             ++nodesInLoop;
46         }
47         //接下来找链表环的入口结点
48         //分三步:
49         //第一步:指针p1和p2初始化时都指向链表头结点
50         //第二步:由于环中有nodesInLoop个结点,指针p1先在链表上向前移动nodesInLoop步
51         //第三步:指针p1和p2以相同速度移动,直到相遇,相遇结点就是环的入口结点
52         pNode1=pHead;
53         for(int i=0;i<nodesInLoop;++i)
54             pNode1=pNode1->next;
55         ListNode* pNode2=pHead;
56         while(pNode1!=pNode2)
57         {
58             pNode1=pNode1->next;
59             pNode2=pNode2->next;
60         }
61         return pNode1;
62     }
63 };

 7.删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
 
 1 /*
 2 struct ListNode {
 3     int val;
 4     struct ListNode *next;
 5     ListNode(int x) :
 6         val(x), next(NULL) {
 7     }
 8 };
 9 */
10 class Solution {
11 public:
12     ListNode* deleteDuplication(ListNode* pHead)
13     {
14         if(pHead==nullptr)
15             return pHead;
16         ListNode dummy(INT_MIN);//头结点
17         dummy.next=pHead;
18         ListNode *prev=&dummy,*cur=pHead;
19         while(cur!=nullptr){
20             bool duplicates=false;
21             while(cur->next!=nullptr&&cur->val==cur->next->val)
22             {
23                 duplicates=true;
24                 ListNode *tmp=cur;
25                 cur=cur->next;
26                 delete tmp;
27             }
28             if(duplicates)
29             {
30                 //删除重复的最后一个元素
31                 ListNode *tmp=cur;
32                 cur=cur->next;
33                 delete tmp;
34                 continue;
35             }
36             prev->next=cur;
37             prev=prev->next;
38             cur=cur->next;
39         }
40         prev->next=cur;
41         return dummy.next;
42     }
43 };

 8.二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
分析二叉树的下一个节点,一共有以下情况: 
1.二叉树为空,则返回空; 
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点; 
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。
 
 1 /*
 2 struct TreeLinkNode {
 3     int val;
 4     struct TreeLinkNode *left;
 5     struct TreeLinkNode *right;
 6     struct TreeLinkNode *next;
 7     TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
 8         
 9     }
10 };
11 */
12 class Solution {
13 public:
14     TreeLinkNode* GetNext(TreeLinkNode* pNode)
15     {
16         if(pNode==NULL)
17             return NULL;
18         TreeLinkNode* pNext=NULL;
19         if(pNode->right!=NULL)
20         {
21             TreeLinkNode* pRight=pNode->right;
22             while(pRight->left!=NULL)
23                 pRight=pRight->left;
24             pNext=pRight;
25         }
26         else if(pNode->next!=NULL)
27         {
28             TreeLinkNode* pCurrent=pNode;
29             TreeLinkNode* pParent=pNode->next;
30             while(pParent!=NULL&&pCurrent==pParent->right)
31             {
32                 pCurrent=pParent;
33                 pParent=pParent->next;
34             }
35             pNext=pParent;
36         }
37         return pNext;
38     }
39 };

 9.对称二叉树

 1 /*
 2 struct TreeNode {
 3     int val;
 4     struct TreeNode *left;
 5     struct TreeNode *right;
 6     TreeNode(int x) :
 7             val(x), left(NULL), right(NULL) {
 8     }
 9 };
10 */
11 
12 class Solution {
13 public:
14     bool help(TreeNode *root1,TreeNode *root2)
15     {
16         if(root1==0)
17             return root2==0;
18         if(root2==0)
19             return false;
20         return(root1->val==root2->val)&&help(root1->left,root2->right)&&help(root1->right,root2->left);
21     }
22     bool isSymmetrical(TreeNode *root)
23     {
24         if(root==0){
25             return true;
26         }
27         return help(root->left,root->right);
28     }
29 };

10.按之字顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
 
 1 /*
 2 struct TreeNode {
 3     int val;
 4     struct TreeNode *left;
 5     struct TreeNode *right;
 6     TreeNode(int x) :
 7             val(x), left(NULL), right(NULL) {
 8     }
 9 };
10 */
11 class Solution {
12 public:
13     vector<vector<int> > Print(TreeNode* pRoot) 
14     {
15         vector<vector<int>> vv;
16         if(pRoot == NULL)
17             return vv;
18         deque<TreeNode *> q;
19         q.push_back(pRoot);
20         bool flag = true;//true表示从左向右存储层次遍历,否则是从右向左
21         int levelCnt = 1;//上一层的节点数目
22         int curLevelCnt = 0;//下一层节点数目
23         vector<int> v;
24         while(!q.empty())
25         {
26             TreeNode *cur;
27             if(flag)
28             {
29                 cur = q.front();
30                 q.pop_front();
31             } 
32             else 
33             {
34                 cur = q.back();
35                 q.pop_back();
36             }
37             if(flag)
38             {
39                 if(cur->left)
40                 {
41                     q.push_back(cur->left);
42                     ++curLevelCnt;
43                 }
44                 if(cur->right)
45                 {
46                     q.push_back(cur->right);
47                     ++curLevelCnt;
48                 }
49             } 
50             else 
51             {
52                 if(cur->right)
53                 {
54                     q.push_front(cur->right);
55                     ++curLevelCnt;
56                 }
57                 if(cur->left)
58                 {
59                     q.push_front(cur->left);
60                     ++curLevelCnt;
61                 }
62             }
63             v.push_back(cur->val);
64             --levelCnt;
65             if(levelCnt == 0)
66             {//这一层完毕
67                 vv.push_back(v);
68                 v.clear();
69                 levelCnt = curLevelCnt;
70                 curLevelCnt = 0;
71                 flag = !flag;
72             }
73         }
74         return vv;
75     }
76 };

 11.把二叉树打印成多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
 1 /*
 2 struct TreeNode {
 3     int val;
 4     struct TreeNode *left;
 5     struct TreeNode *right;
 6     TreeNode(int x) :
 7             val(x), left(NULL), right(NULL) {
 8     }
 9 };
10 */
11 class Solution {
12 public:
13         vector<vector<int> > Print(TreeNode* pRoot)
14         {
15             vector<vector<int> > result;
16             queue<TreeNode*> current,next;
17             if(pRoot==NULL)
18                 return result;
19             else
20                 current.push(pRoot);
21             while(!current.empty()){
22                 vector<int> level;//元素在一层
23                 while(!current.empty()){
24                     TreeNode* node=current.front();
25                     current.pop();
26                     level.push_back(node->val);
27                     if(node->left!=NULL)
28                         next.push(node->left);
29                     if(node->right!=NULL)
30                         next.push(node->right);
31                 }
32                 result.push_back(level);
33                 swap(next,current);
34             }
35             return result;
36       }
37 };

12.二叉搜索树的第k个结点

 1 /*
 2 struct TreeNode {
 3     int val;
 4     struct TreeNode *left;
 5     struct TreeNode *right;
 6     TreeNode(int x) :
 7             val(x), left(NULL), right(NULL) {
 8     }
 9 };
10 */
11 class Solution {
12 public:
13     //按照中序遍历的顺序遍历一颗二叉搜索树,遍历序列的数值是递增排序的
14     TreeNode* KthNode(TreeNode* pRoot, int k)
15     {
16         if(pRoot==NULL||k==0)
17             return NULL;
18         return KthNodeCore(pRoot,k);
19     }
20     TreeNode* KthNodeCore(TreeNode* pRoot, int& k)
21     {
22         TreeNode* target=NULL;
23         if(pRoot->left!=NULL)
24             target=KthNodeCore(pRoot->left,k);
25         if(target==NULL)
26         {
27             if(k==1)
28                 target=pRoot;
29             k--;
30         }
31         if(target==NULL&&pRoot->right!=NULL)
32             target=KthNodeCore(pRoot->right,k);
33         return target;
34     }
35 };

 

posted @ 2017-08-23 09:57  walanwalan  阅读(248)  评论(0编辑  收藏  举报