剑指offer

tech2024-06-14  54

这里写自定义目录标题

输入输出练习面试题4 二维数组中的查找面试题5 替换空格面试题6 从尾到头打印链表面试题7 重建二叉树面试题8 二叉树的下一个节点面试题9 用两个栈实现队列面试题10 斐波那契数列跳台阶**变态跳台阶**矩形覆盖 面试题11 旋转数组的最小数字面试题15 二进制中1的个数面试题16 数值的整数次幂---待看面试题21 调整数组顺序使奇数位于偶数前面面试题22 链表中倒数第k个节点面试题24 翻转链表面试题25 合并两个排序的链表面试题26 树的子结构面试题27 二叉树的镜像面试题28 对称的二叉树面试题29 顺时针打印矩阵面试题30 包含min函数的栈面试题31 栈的压入、弹出序列面试题32 从上到下打印二叉树面试题33 二叉搜索树的后序遍历序列面试题34 二叉树中和为某一值的路径面试题35 复杂链表的复制--待看面试题38 字符串的排列面试题39 数组中出现次数超过一半的数字面试题40 最小的k个数面试题41 数据流中的中位数面试题42 连续子数组的最大和面试题43 1~n整数中1出现的次数面试题44 数字序列中某一位的数字面试题45 把数组排成最小的数面试题46 把数字翻译成字符串面试题47 礼物的最大价值面试题48 最长不含重复字符的子字符串面试题49 丑数面试题50 第一个只出现一次的字符字符流中第一个不重复的字符面试题51 数组中的逆序对面试题52 两个链表的第一个公共节点面试题53 在排序数组中查找数字**题目一 数字在排序数组中出现的次数****题目二 0~n-1中缺失的数字**题目三 数组中数值和下标相等的元素 面试题54 二叉搜索树的第k大节点面试题55 二叉树的深度题目一 二叉树的深度题目二 平衡二叉树 面试题56 数组中数字出现的次数题目一 数组中只出现一次的两个数字题目二 数组中唯一只出现一次的数字--待看 面试题57 和为s的数字题目一 和为s的两个数字

输入输出练习

Java有关语法

next()从遇到第一个有效字符(非空格、换行符)开始扫描,遇到第一个分隔符或结束符(空格’ ‘或者换行符 ‘\n’)时结束。 nextLine()则是扫描剩下的所有字符串直到遇到回车为止

A+B(1)

/*输入包括两个正整数a,b(1 <= a, b <= 10^9),输入数据包括多组。 输入 1 5 10 20 输出 6 30 */ #include<iostream> using namespace std; int main(){ int a,b; while(cin>>a>>b) count<<a+b<<endl; return 0; } while True: try: ls = input().split() x = int(ls[0]) y = int(ls[1]) print(x+y) except: break import java.util.Scanner public class Main{ public static void main(String[] args){ Scanner in = new Scanner(System.in); while(in.hasNextInt()){ int a = in.nextInt(); int b = in.nextInt(); System.out.println(a+b); } } }

A+B(2)

链接:https://ac.nowcoder.com/acm/contest/5649/B 来源:牛客网 输入第一行包括一个数据组数t(1 <= t <= 100) 接下来每行包括两个正整数a,b(1 <= a, b <= 10^9)

输入 2 1 5 10 20

输出 6 30

#include<iostream> using namespace std; int main(){ int t, a, b; cin>>t; for(int i = 0; i<t; i++){ cin >> a >> b; cout << a+b <<endl; } return 0; } n = int(input()) for i in range(n): cal = [int(x) for x in input().split()] print(sum(cal)) import java.util.Scanner; public class AB2 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int c = sc.nextInt(); for(int i=0; i<c; i++){ int a = sc.nextInt(); int b = sc.nextInt(); System.out.println(a+b); } } }

A+B(3)

链接:https://ac.nowcoder.com/acm/contest/5649/C 来源:牛客网 输入包括两个正整数a,b(1 <= a, b <= 10^9),输入数据有多组, 如果输入为0 0则结束输入

输入 1 5 10 20 0 0

输出 6 30

#include <iostream> using namespace std; int main(){ int a, b; while(cin>>a>>b && a!=0 && b!=0){ cout << a+b <<endl; } return 0; } while true: try: ls = input().split() a = int(ls[0]) b = int(ls[1]) if a=0 and b=0: break else: print(a+b) except e: break import java.util.*; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); while(sc.hasNext()){ int a = sc.nextInt(); int b = sc.nextInt(); if(a==0 && b==-0) break; System.out.println(a+b); } } }

A+B(4)

链接:https://ac.nowcoder.com/acm/contest/5649/D 来源:牛客网 输入数据包括多组。 每组数据一行,每行的第一个整数为整数的个数n(1 <= n <= 100), n为0的时候结束输入。 接下来n个正整数,即需要求和的每个正整数。

输入 4 1 2 3 4 5 1 2 3 4 5 0

输出 10 15

#include<iostream> using namespace std; int main(){ int n=0; while(cin>>n){ if(n==0) break; int a; int sum=0; for(int i=0; i<n;i++){ cin>>a; sum += a; } cont << sum<<end; } return 0; } while True: nums = input().split() addrs = map(int, nums[1:]) if int(nums[0]) == 0: break else: print(sum(addrs)) import java.util.Scanner; public class AB4 { public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNextInt()){ int n = in.nextInt(); if(n==0){ break; } int sum = 0; for (int i = 0; i < n; i++){ int a = in.nextInt(); sum += a; } System.out.println(sum); } } }

A+B(5)

链接:https://ac.nowcoder.com/acm/contest/5649/E 来源:牛客网

输入的第一行包括一个正整数t(1 <= t <= 100), 表示数据组数。 接下来t行, 每行一组数据。 每行的第一个整数为整数的个数n(1 <= n <= 100)。 接下来n个正整数, 即需要求和的每个正整数。

输入 2 4 1 2 3 4 5 1 2 3 4 5

输出 10 15

#include<iostream> using namespace std; int main(){ int t; cin>>t; for(int i=0;i<t;i++){ int n; cin>>n; int sum = 0, tmp=0; for (int j=0;j<n;++j){ cin >> tmp; sum += tmp; } cout<<sum<<endl; } } n = int(input()) for i in range(n): num = list(map(int, input().split())) print(num[1:num[0]+1]) import java.util.Scanner; public class AB5 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int num = sc.nextInt(); for(int i=0;i<num;i++){ int items = sc.nextInt(); int sum =0; for (int j=0; j<items;j++) sum += sc.nextInt(); System.out.println(sum); } } }

A+B(7)

链接:https://ac.nowcoder.com/acm/contest/5649/G 来源:牛客网

输入数据有多组, 每行表示一组输入数据。 每行不定有n个整数,空格隔开。(1 <= n <= 100)。

输入 1 2 3 4 5 0 0 0 0 0

输出 6 9 0

#include<iostream> using namespace std; int main(){ int tmp; char c; int sum=0; while(cin>>tmp){ cin.get(c); sum+=tmp; if(c=='\n'){ cout<<sum<<endl; sum=0; } } return 0; } import sys for line in sys.stdin.readlines(): L = list(map(int,line.strip().split())) print(sum(L)) #https://blog.csdn.net/CAU_Ayao/article/details/81985103 #input()方法和stdin()类似,不同的是input()括号内可以直接填写说明文字。 while True: try: print(sum(list(map(int,input().strip().split())))) except: break import java.util.Scanner; public class AB7 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNextLine()){ String[] line = sc.nextLine().split(" "); int sum = 0; for(int i =0; i< line.length;i++){ sum += Integer.parseInt(line[i]); } System.out.println(sum); } } }

字符串排序

输入有两行,第一行n第二行是n个空格隔开的字符串

输入 5 c d a bb e

输出 a bb c d e

#include<iostream> using namespace std; int main(){ int n; cin>>n; vector<string> arr; string tmp; for(int i=0;i<n;i++){ cin>>tmp; arr.push_back(tmp); } sort(arr.brgin(), arr.end()); for(auto s:srr) cout <<s<<endl; } n = int(input()) arr = input().split() arr.sort() s = ' '.join(arr) print(s) import java.util.Arrays; import java.util.Scanner; public class string_sort1 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = Integer.parseInt(sc.nextLine()); String[] strs = sc.nextLine().split(" "); Arrays.sort(strs); //System.out.println(String.join(" ", strs)); 同下 String nStr = ""; for(int i=0;i<n;i++){ nStr = nStr+strs[i]; if(i != n-1) nStr = nStr + " "; } System.out.println(nStr); } }

字符串排序(2)

多个测试用例,每个测试用例一行。每行通过空格隔开,有n个字符,n<100。

对于每组测试用例,输出一行排序过的字符串,每个字符串通过空格隔开

输入 a c bb f dddd nowcoder

输出 a bb c dddd f nowcoder

#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; int main() { string s; vector<string> str; char c = ' '; while(cin >> s) { str.push_back(s); c = cin.get(); if(c == '\n') { sort(str.begin(), str.end()); for(int i=0; i< str.size(); i++) { cout << str[i] << ' '; } cout << endl; str.clear(); } } return 0; } import sys for line in sys.stdin: x=list(line.split()) x.sort() print(' '.join(x)) import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); while(sc.hasNext()){ String[] arr = sc.nextLine().split(" "); Arrays.sort(arr); System.out.println(String.join(" ", arr)); } sc.close(); } }

字符串排序(3)

面试题4 二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution { public: bool Find(int target, vector<vector<int>> array) { if(array.empty()) return false; int rows = array.size(); int columns = array[0].size(); bool found = false; int row = 0; int column = columns-1; while(row < rows && column >= 0){ //依次从右上角向左下角的方向进行 if(array[row][column] == target){ found = true; break; } else if(array[row][column] > target) column--; else row++; } return found; } };

面试题5 替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

// class Solution { public: void replaceSpace(char *str,int length) { if( str == nullptr || length<=0) return; int originalLength = 0; int numberOfBlank = 0; int i = 0; while(str[i] != '\0'){ originalLength++; if(str[i] == ' ') numberOfBlank++; i++; } int newLength = originalLength + numberOfBlank*2; //indexOfOriginal指针指向原字符串末尾 int indexOfOriginal = originalLength; //indexOfNew指针指向信字符串末尾 int indexOfNew = newLength; //两个指针依次向前移动,原字符串复制到新字符串位置,如果有空格,indexOfOriginal向前移动一位,indexOfNew向前移动三位,依次赋值“ %20 ” while(indexOfOriginal>=0 && indexOfNew>indexOfOriginal){ if(str[indexOfOriginal] != ' ') str[indexOfNew--] = str[indexOfOriginal]; else{ str[indexOfNew--] = '0'; str[indexOfNew--] = '2'; str[indexOfNew--] = '%'; } indexOfOriginal--; } } };

面试题6 从尾到头打印链表

/** * struct ListNode { * int val; * struct ListNode *next; * ListNode(int x) : * val(x), next(NULL) { * } * }; */ class Solution { public: vector<int> printListFromTailToHead(ListNode* head) { vector<int> result; stack<int> arr; //栈,先进后出 ListNode* pNode = head; while(pNode != nullptr){ arr.push(pNode->val); //push 压入 pNode = pNode->next; } while(!arr.empty()){ result.push_back(arr.top()); //push_back arr.pop(); //pop 弹出 } return result; } };

面试题7 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { int n = pre.size(); int m = vin.size(); if(n!=m || n==0) return nullptr; return construct(pre, vin, 0, n-1, 0, m-1); } TreeNode* construct(vector<int> pre, vector<int> vin, int l1, int r1, int l2, int r2){ TreeNode* root = new TreeNode(pre[l1]); if(r1 == l1) return root; int val = pre[l1]; int index; for(index=l2; index<=r2; index++){ if(vin[index] == val) break; } int left_tree_len = index-l2; int right_tree_len = r2 - index; if(left_tree_len > 0) root->left = construct(pre, vin, l1+1, l1+left_tree_len, l2, index-1); if(right_tree_len > 0) root->right = construct(pre, vin, l1+1+left_tree_len, r1, index+1, r2); return root; } }; //前序遍历序列 1 2 4 7 3 5 6 8 // | _____ _______ // 根 左 右 //中序遍历序列 4 7 2 1 5 3 8 6 // ______ | ——————— // 左 根 右

面试题8 二叉树的下一个节点

面试题9 用两个栈实现队列

class Solution { public: void push(int node) { stack1.push(node); } int pop() { if(stack2.size()<=0){ while(stack1.size() > 0){ stack2.push(stack1.top()); stack1.pop(); } } int result = stack2.top(); stack2.pop(); return result; } private: stack<int> stack1; stack<int> stack2; };

面试题10 斐波那契数列

跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。f(n) = f(n-1) + f(n-2)

class Solution { public: int jumpFloor(int number) { int result[3] = {0, 1, 2}; if(number <= 2) return result[number]; int fibOne = 2; int fibTwo = 1; int fibN = 0; for(int i = 3; i<=number; i++){ fibN = fibOne + fibTwo; fibTwo = fibOne; fibOne = fibN; } return fibN; } };

变态跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。所以f(n)=f(n-1)+f(n-2)+…+f(1),因为f(n-1)=f(n-2)+f(n-3)+…+f(1)所以f(n)=2*f(n-1)

class Solution { public: int jumpFloorII(int number) { if(number<=0) return -1; vector<int> res(number+1); res[0] = 1; res[1] = 1; for(int i=2; i<=number; i++){ res[i] = res[i-1]*2; } return res[number]; } };

矩形覆盖

同菲波那切数列

class Solution { public: int rectCover(int number) { int result[3] = {0, 1, 2}; if(number <= 2) return result[number]; int fibOne = 2; int fibTwo = 1; int fibN = 0; for(int i = 3; i<=number; i++){ fibN = fibOne + fibTwo; fibTwo = fibOne; fibOne = fibN; } return fibN; } };

面试题11 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

class Solution { public: int minNumberInRotateArray(vector<int> rotateArray) { if(rotateArray.size() == 0) return 0; int index1 = 0; int index2 = rotateArray.size()-1; int indexMid = index1; while(rotateArray[index1] >= rotateArray[index2]){ if(index2 - index1 == 1){ indexMid = index2; break; } indexMid = (index1+index2)/2; //如果下标 if(rotateArray[index1] == rotateArray[index2]&&rotateArray[index2] == rotateArray[indexMid]) return MinInOrder(rotateArray, index1, index2); if(rotateArray[indexMid]>=rotateArray[index1]) index1 = indexMid; else if(rotateArray[indexMid] <= rotateArray[index2]) index2 = indexMid; } return rotateArray[indexMid]; } int MinInOrder(vector<int> rotateArray, int index1, int index2){ int result = rotateArray[index1]; for(vector<int>::iterator it= rotateArray.begin(); it!=rotateArray.end(); it++ ){ if(result>*it) result = *it; } return result; } };

面试题15 二进制中1的个数

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

//如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 //举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。 class Solution { public: int NumberOf1(int n) { int count = 0; while(n){ count++; n=(n-1)&n; //先减去1,再做与运算,会把整数最右边1变为0 } return count; } };

面试题16 数值的整数次幂—待看

class Solution { public: bool g_InvalidInput = false; double Power(double base, int exponent) { g_InvalidInput = false; if(base==0.0&&exponent<0){ g_InvalidInput = true; return 0.0; } unsigned int absExponent = (unsigned int)(exponent); if(exponent < 0) absExponent = (unsigned int)(-exponent); double result = PowerWithUnsignedExponent(base, absExponent); if(exponent < 0) result = 1.0/result; return result; } double PowerWithUnsignedExponent(double base, unsigned int absExponent){ if(absExponent==0) return 1; if(absExponent==1) return base; double result = PowerWithUnsignedExponent(base, absExponent>>1); result*=result; if(absExponent&1==1) result*=base; return result; } };

面试题21 调整数组顺序使奇数位于偶数前面

//需要保证调整后数据的相对顺序不变 class Solution { public: void reOrderArray(vector<int> &array) { if(array.empty()) return; int i=0, j; while(i<array.size()){ while(i<array.size() && !isEven(array[i])) i++; //while循环结束此i++为第一个偶数 j=i+1; while(j<array.size() && isEven(array[j])) j++; if(j<array.size()){ int temp = array[j]; for(int k=j-1; k>=i; k--) array[k+1] = array[k]; array[i++] = temp; } else break; } } bool isEven(int n){ return (n&1)==0; //偶数返回true; } }; //不需要保证相对顺序 class Solution { public: void reOrderArray(vector<int> &array) { if(array.empty()) return; int pBegin=0; int pEnd = array.size(); while(pBegin < pEnd){ while(pBegin < pEnd && isEven(array[pBegin])) pBegin++; while(pBegin < pEnd && !isEven(array[End])) pEnd--; if(pBegin < pEnd){ swap(array[pBegin], array[pEnd]) } } } bool isEven(int n){ return (n&1)==0; //偶数返回true; } };

面试题22 链表中倒数第k个节点

/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { if(pListHead==nullptr||k==0) return nullptr; ListNode *pAhead=pListHead; ListNode *pBehind = pListHead; for(unsigned int i=0; i<k-1; i++){ if(pAhead->next != nullptr) pAhead = pAhead->next; else return nullptr; } while(pAhead->next != nullptr){ pAhead = pAhead->next; pBehind = pBehind->next; } return pBehind; } };

面试题24 翻转链表

/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* ReverseList(ListNode* pHead) { ListNode* pReverseHead = nullptr; ListNode* pNode = pHead; ListNode* pPrev = nullptr; while(pNode!=nullptr){ ListNode* pNext = pNode->next; if(pNext==nullptr) pReverseHead = pNode; pNode->next = pPrev; pPrev = pNode; pNode = pNext; } return pReverseHead; } }; // ____ ____ _____ // | | | // pPrev pNode pNext

面试题25 合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* Merge(ListNode* pHead1, ListNode* pHead2) { if(pHead1==nullptr) return pHead2; else if(pHead2 == nullptr) return pHead1; ListNode* pMergedHead = nullptr; if(pHead1->val < pHead2->val){ //递归 pMergedHead = pHead1; pMergedHead->next = Merge(pHead1->next, pHead2); }else{ pMergedHead = pHead2; pMergedHead->next = Merge(pHead2->next, pHead1); } return pMergedHead; } };

面试题26 树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构

/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) //pRoot2树是子树 { bool result = false; if(pRoot1!=nullptr && pRoot2!=nullptr){ if(pRoot1->val == pRoot2->val) result = DoesTree1HaveTree2(pRoot1, pRoot2); if(!result) result = HasSubtree(pRoot1->left, pRoot2); if(!result) result = HasSubtree(pRoot1->right, pRoot2); } return result; } bool DoesTree1HaveTree2(TreeNode* pRoot1, TreeNode* pRoot2){ if(pRoot2 == nullptr) return true; if(pRoot1 == nullptr) return false; if(pRoot1->val != pRoot2->val) return false; return DoesTree1HaveTree2(pRoot1->left, pRoot2->left)&&DoesTree1HaveTree2(pRoot1->right,pRoot2->right); } };

面试题27 二叉树的镜像

/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: void Mirror(TreeNode *pRoot) { if(pRoot==nullptr) return; if(pRoot->left == nullptr && pRoot->right == nullptr) return; TreeNode *pTemp = pRoot->left; pRoot->left = pRoot->right; pRoot->right = pTemp; if(pRoot->left) Mirror(pRoot->left); if(pRoot->right) Mirror(pRoot->right); } };

面试题28 对称的二叉树

面试题29 顺时针打印矩阵

class Solution { public: vector<int> printMatrix(vector<vector<int> > matrix) { int rows = matrix.size(); int columns = matrix[0].size(); vector<int> result; // push_back() if(rows<=0 || columns<=0) return result; int left=0,right=columns-1,top=0,bottom=rows-1; while(left<=right&&top<=bottom){ //从左到右打印一行 for(int i=left; i<=right; i++) result.push_back(matrix[top][i]); //从上到下打印一列 if(top<bottom) for(int j=top+1; j<=bottom;j++) result.push_back(matrix[j][right]); //从右到左打印一行 if(left<right&&top<bottom) for(int k=right-1;k>=left;k--) result.push_back(matrix[bottom][k]); if(left<right&&top+1<bottom) for(int m=bottom-1;m>=top+1;m--) result.push_back(matrix[m][left]); left++;right--;top++;bottom--; } return result; } };

面试题30 包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

class Solution { public: void push(int value) { m_data.push(value); //栈的操作 push(), pop(), top() if(m_min.empty()) m_min.push(value); else if(m_min.top() >= value) m_min.push(value); else m_min.push(m_min.top()); } void pop() { m_data.pop(); m_min.pop(); } int top() { return m_data.top(); } int min() { return m_min.top(); } private: stack<int> m_data; //数据栈 stack<int> m_min; //辅助栈 };

面试题31 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

class Solution { public: bool IsPopOrder(vector<int> pushV,vector<int> popV) { stack<int> st; //辅助栈 int id = 0; for(int i = 0; i<popV.size(); i++){ while(st.empty() || st.top() != popV[i]){ st.push(pushV[id++]); if(id > pushV.size()) return false; } st.pop(); //不满足while条件弹出栈顶元素 } if(st.empty()) return true; else return false; } };

面试题32 从上到下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: vector<int> PrintFromTopToBottom(TreeNode* root) { vector<int> result; if(!root) return result; deque<TreeNode*> dq; dq.push_back(root); //push_back() while(dq.size() > 0){ TreeNode* pNode = dq.front(); //front() dq.pop_front(); //pop_front() result.push_back(pNode->val); if(pNode->left) dq.push_back(pNode->left); if(pNode->right) dq.push_back(pNode->right); } return result; } };

面试题33 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。

//左子树一定比右子树小,因此去掉根后,数字分为left,right两部分,right部分的 //最后一个数字是右子树的根他也比左子树所有值大,因此我们可以每次只看有子树是否符合条件 //即可,即使到达了左子树左子树也可以看出由左右子树组成的树还想右子树那样处理 //对于左子树回到了原问题,对于右子树,左子树的所有值都比右子树的根小可以暂时把他看出右子树的左子树 //只需看看右子树的右子树是否符合要求即可 class Solution { public: bool VerifySquenceOfBST(vector<int> sequence) { int length = sequence.size(); if(length == 0) return false; int i = 0; while(--length){ while(sequence[i++] < sequence[length]); while(sequence[i++] > sequence[length]); if(i < length) return false; i=0; } return true; } };

面试题34 二叉树中和为某一值的路径

输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: vector<vector<int> > FindPath(TreeNode* root,int expectNumber) { if(!root) return result; path.push_back(root->val); if((expectNumber - root->val == 0) && root->left == nullptr && root->right == nullptr) result.push_back(path); FindPath(root->left, expectNumber - root->val); FindPath(root->right, expectNumber - root->val); //在返回父节点之前,在路径上删除当前节点 path.pop_back(); return result; } private: vector<vector<int>> result; vector<int> path; };

面试题35 复杂链表的复制–待看

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

/* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomListNode(int x) : label(x), next(NULL), random(NULL) { } }; */ class Solution { public: void CloneNode(RandomListNode* pHead){ RandomListNode* pNode = pHead; while(pNode!=nullptr){ RandomListNode* pCloned = new RandomListNode(pNode->label); //pCloned->label = pNode->label; pCloned->next = pNode->next; pCloned->random = nullptr; pNode->next = pCloned; pNode = pCloned->next; } } void ConnectSiblingNodes(RandomListNode* pHead){ RandomListNode* pNode = pHead; while(pNode != nullptr){ RandomListNode* pCloned = pNode->next; if(pNode->random != nullptr) pCloned->random = pNode->random->next; pNode = pCloned->next; } } RandomListNode* ReconnectNodes(RandomListNode* pHead){ RandomListNode* pNode = pHead; RandomListNode* pCloneHead = nullptr; RandomListNode* pCloneNode = nullptr; if(pNode != nullptr){ pCloneHead = pCloneNode = pNode->next; pNode->next = pCloneNode->next; pNode = pNode->next; } while(pNode != nullptr){ pCloneNode->next = pNode->next; pCloneNode = pCloneNode->next; pNode->next= pCloneNode->next; pNode = pNode->next; } return pCloneHead; } RandomListNode* Clone(RandomListNode* pHead) { if(pHead==nullptr) return nullptr; CloneNode(pHead); ConnectSiblingNodes(pHead); return ReconnectNodes(pHead); } };

面试题36 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { if(pRootOfTree == nullptr) return nullptr; TreeNode* pre = nullptr; convertHelper(pRootOfTree, pre); TreeNode* res = pRootOfTree; while(res ->left) res = res ->left; return res; //树最左边的节点就是头结点 返回 } void convertHelper(TreeNode* cur, TreeNode*& pre) { if(cur == nullptr) return; convertHelper(cur ->left, pre); cur ->left = pre; if(pre) pre ->right = cur; pre = cur; convertHelper(cur ->right, pre); } }; //原先指向左子节点的指针调整为链表中指向掐一个节点的指针,原先指向右子节点的指针调整为链表中指向后一个节点的指针 //中序遍历算法的特点就是按照从小到大的顺序遍历二叉树种的每个节点

面试题38 字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

https://www.cnblogs.com/cxjchen/p/3932949.html

/** * 1、递归算法 * * 解析:http://www.cnblogs.com/cxjchen/p/3932949.html (感谢该文作者!) * * 对于无重复值的情况 * * 固定第一个字符,递归取得首位后面的各种字符串组合; * 再把第一个字符与后面每一个字符交换,并同样递归获得首位后面的字符串组合; *递归的出口,就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。 * * 假如有重复值呢? * *由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。 * 例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。 * 但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。 * 由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。 * * 换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数, * 所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕! */ //参照剑指offer的思路 class Solution { public: vector<string> Permutation(string str) { vector<string> res; if(str.empty()) return res; string tmp=""; recur(str,res,tmp,0); return res; } void recur(string str,vector<string> &res,string &tmp,int start){ if(start==str.size()){ res.push_back(tmp); return; } for(int i=start;i<str.size();i++){ //判断要交换的字符是否相同,相同就不用交换直接跳过(除了start位置与自己交换的情况) if(i!=start&&str[start]==str[i]) continue; swap(str[start],str[i]); tmp+=str[start]; recur(str,res,tmp,start+1); tmp.pop_back(); } } };

面试题39 数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

class Solution { public: int MoreThanHalfNum_Solution(vector<int> numbers) { if(numbers.empty()) return 0; int result = numbers[0]; int times = 1; for(int i = 1; i<numbers.size(); i++){ if(times == 0){ result = numbers[i]; times = 1; }else if(result == numbers[i]) times++; else times--; } times = 0; for(int i = 0; i<numbers.size(); i++) if(result == numbers[i]) times++; return (times > numbers.size()/2) ? result:0; } };

面试题40 最小的k个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。

class Solution { public: vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { vector<int> result; if(input.empty() || k <= 0 || k>input.size()) return result; int start = 0; int end = input.size()-1; int index = Partition(input, start, end); while(index != k-1){ if(index > k-1){ end = index-1; index = Partition(input, start, end); } else{ start = index+1; index = Partition(input, start, end); } } for(int i = 0; i<k; i++) result.push_back(input[i]); return result; } int Partition(vector<int>& input, int l, int r){ swap(input[l], input[rand() % (r-l+1 )+l]); int T = input[l]; int i = l+1; int j = r; while(true){ while(i <= r && input[i] < T) i++; while(j >= l+1 && input[j] > T) j--; if(i > j) break; swap(input[i], input[j]); i++; j--; } swap(input[l], input[j]); return j; } };

面试题41 数据流中的中位数

面试题42 连续子数组的最大和

输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数

class Solution { public: int FindGreatestSumOfSubArray(vector<int> array) { if(array.empty()) return 0; int maxsum = INT_MIN; int cursum = 0; for(int i = 0; i<array.size(); i++){ if(cursum <= 0) cursum = array[i]; else cursum += array[i]; if(cursum > maxsum) maxsum = cursum; } return maxsum; } };

面试题43 1~n整数中1出现的次数

输入一个整数n,求1~n这n个整数的十进制表示中1出现的次数。

像类似这样的问题,我们可以通过归纳总结来获取相关的东西。

首先可以先分类:

个位

我们知道在个位数上,1会每隔10出现一次,例如1、11、21等等,我们发现以10为一个阶梯的话,每一个完整的阶梯里面都有一个1,例如数字22,按照10为间隔来分三个阶梯,在完整阶梯0-9,10-19之中都有一个1,但是19之后有一个不完整的阶梯,我们需要去判断这个阶梯中会不会出现1,易推断知,如果最后这个露出来的部分小于1,则不可能出现1(这个归纳换做其它数字也成立)。

我们可以归纳个位上1出现的个数为:

n/10 * 1+(n%10!=0 ? 1 : 0)

十位

现在说十位数,十位数上出现1的情况应该是10-19,依然沿用分析个位数时候的阶梯理论,我们知道10-19这组数,每隔100出现一次,这次我们的阶梯是100,例如数字317,分析有阶梯0-99,100-199,200-299三段完整阶梯,每一段阶梯里面都会出现10次1(从10-19),最后分析露出来的那段不完整的阶梯。我们考虑如果露出来的数大于19,那么直接算10个1就行了,因为10-19肯定会出现;如果小于10,那么肯定不会出现十位数的1;如果在10-19之间的,我们计算结果应该是k - 10 + 1。例如我们分析300-317,17个数字,1出现的个数应该是17-10+1=8个。

那么现在可以归纳:十位上1出现的个数为:

设k = n % 100,即为不完整阶梯段的数字归纳式为:(n / 100) * 10 + (if(k > 19) 10 else if(k < 10) 0 else k - 10 + 1)

百位

现在说百位1,我们知道在百位,100-199都会出现百位1,一共出现100次,阶梯间隔为1000,100-199这组数,每隔1000就会出现一次。这次假设我们的数为2139。跟上述思想一致,先算阶梯数 * 完整阶梯中1在百位出现的个数,即n/1000 * 100得到前两个阶梯中1的个数,那么再算漏出来的部分139,沿用上述思想,不完整阶梯数k199,得到100个百位1,100<=k<=199则得到k - 100 + 1个百位1。

那么继续归纳百位上出现1的个数:

设k = n % 1000归纳式为:(n / 1000) * 100 + (if(k >199) 100 else if(k < 100) 0 else k - 100 + 1)

后面的依次类推…

再次回顾个位

我们把个位数上算1的个数的式子也纳入归纳式中

k = n % 10个位数上1的个数为:n / 10 * 1 + (if(k > 1) 1 else if(k < 1) 0 else k - 1 + 1)

完美!归纳式看起来已经很规整了。 来一个更抽象的归纳,设i为计算1所在的位数,i=1表示计算个位数的1的个数,10表示计算十位数的1的个数等等。

k = n % (i * 10)count(i) = (n / (i * 10)) * i + (if(k > i * 2 - 1) i else if(k < i) 0 else k - i + 1)

好了,这样从10到10的n次方的归纳就完成了。

sum1 = sum(count(i)),i = Math.pow(10, j), 0<=j<=log10(n)

但是有一个地方值得我们注意的,就是代码的简洁性来看,有多个ifelse不太好,能不能进一步简化呢? 我们可以把后半段简化成这样,我们不去计算i * 2 - 1了,我们只需保证k - i + 1在[0, i]区间内就行了,最后后半段可以写成这样

min(max((n mod (i*10))−i+1,0),i)

class Solution { public: int NumberOf1Between1AndN_Solution(int n) { if(n <= 0) return 0; int count = 0; for(long i = 1; i <= n; i *= 10){ long diviver = i * 10; count += (n / diviver) * i + MIN(MAX(n % diviver - i + 1, 0), i); } return count; } int MIN(int a, int b){ return (a < b ? a : b ); } int MAX(int a, int b){ return (a > b ? a : b); } };

面试题44 数字序列中某一位的数字

面试题45 把数组排成最小的数

/*对vector容器内的数据进行排序,按照 将a和b转为string后 若 a+b<b+a a排在在前 的规则排序, 如 2 21 因为 212 < 221 所以 排序后为 21 2 to_string() 可以将int 转化为string */ class Solution { public: static bool cmp(int a, int b){ string A = ""; string B = ""; A += to_string(a); A += to_string(b); B += to_string(b); B += to_string(a); return A<B; } string PrintMinNumber(vector<int> numbers) { string res = ""; sort(numbers.begin(), numbers.end(),cmp); //sort排序 for(int i=0; i<numbers.size(); i++){ res += to_string(numbers[i]); } return res; } };

面试题46 把数字翻译成字符串

面试题47 礼物的最大价值

面试题48 最长不含重复字符的子字符串

面试题49 丑数

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

class Solution { public: int GetUglyNumber_Solution(int index) { if(index <= 0) return 0; int *pUglyNumbers = new int[index]; pUglyNumbers[0] = 1; int nextUglyIndex = 1; int *pUglyNumbers2 = pUglyNumbers; int *pUglyNumbers3 = pUglyNumbers; int *pUglyNumbers5 = pUglyNumbers; while(nextUglyIndex < index){ int min = Min(*pUglyNumbers2 * 2, *pUglyNumbers3 * 3, *pUglyNumbers5 * 5); pUglyNumbers[nextUglyIndex] = min; while(*pUglyNumbers2 * 2 <= pUglyNumbers[nextUglyIndex]) ++pUglyNumbers2; while(*pUglyNumbers3 * 3 <= pUglyNumbers[nextUglyIndex]) ++pUglyNumbers3; while(*pUglyNumbers5 * 5 <= pUglyNumbers[nextUglyIndex]) ++pUglyNumbers5; ++nextUglyIndex; } int ugly = pUglyNumbers[nextUglyIndex - 1]; delete[] pUglyNumbers; return ugly; } int Min(int numbers1, int numbers2, int numbers3){ int min = (numbers1 < numbers2) ? numbers1 : numbers2; min = (min < numbers3) ? min:numbers3; return min; } }; class Solution { public: int GetUglyNumber_Solution(int index) { // 0-6的丑数分别为0-6 if(index < 7) return index; //p2,p3,p5分别为三个队列的指针,newNum为从队列头选出来的最小数 int p2 = 0, p3 = 0, p5 = 0, newNum = 1; vector<int> arr; arr.push_back(newNum); while(arr.size() < index) { //选出三个队列头最小的数 newNum = min(arr[p2] * 2, min(arr[p3] * 3, arr[p5] * 5)); //这三个if有可能进入一个或者多个,进入多个是三个队列头最小的数有多个的情况 if(arr[p2] * 2 == newNum) p2++; if(arr[p3] * 3 == newNum) p3++; if(arr[p5] * 5 == newNum) p5++; arr.push_back(newNum); } return newNum; } };

面试题50 第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

class Solution { public: int FirstNotRepeatingChar(string str) { if(str.size() == 0) return -1; char hashMap[256] = {0}; for(int i=0; i<str.size(); i++) hashMap[str[i]]++; for(int j=0; j<str.size(); j++) if(hashMap[str[j]] == 1) return j; return -1; //返回位置 } };

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

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"

//class Solution //{ //private: // int occurrence[256]; // int index; // //public: // Solution(){ // for(int i=0;i<256;i++) // occurrence[i] = -1; // index=0; // } //Insert one char from stringstream // void Insert(char ch) // { // if(occurrence[ch]==-1) // occurrence[ch]=index; // else if(occurrence[ch]>=0) // occurrence[ch]=-2; // index++; // } //return the first appearence once char in current stringstream // char FirstAppearingOnce() // { // char ch='\0'; // int minIndex = INT_MAX; // for(int i=0;i<256;++i){ // if(occurrence[i]>=0 && occurrence[i]<minIndex){ // ch=char(i); // minIndex=occurrence[i]; // } // } // if (ch=='\0') // ch = '#'; // return ch; // } //}; class Solution { public: //Insert one char from stringstream string s; char hash[256]={0}; void Insert(char ch) { s+=ch; hash[ch]++; } //return the first appearence once char in current stringstream char FirstAppearingOnce() { int size=s.size(); for(int i=0;i<size;++i) { if(hash[s[i]]==1) return s[i]; } return '#'; } };

面试题51 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

//先把数组分割成子数组,统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。在统计逆序对的过程中,还需要对数组 进行排序, //排序的过程为归并排序 class Solution { public: int InversePairs(vector<int> data) { int length = data.size(); if(length <= 0) return 0; vector<int> copy; for(int i=0; i<length; i++) copy.push_back(data[i]); long long count = InversePairCore(data, copy, 0, length-1); return count%1000000007; } long long InversePairCore(vector<int> &data, vector<int> &copy, int start, int end){ if(start == end){ copy[start]=data[start]; return 0; } int length = (end-start)/2; long long left = InversePairCore(copy, data, start, start+length); long long right = InversePairCore(copy, data, start+length+1, end); int i = start+length; int j = end; int indexCopy = end; long long count = 0; while(i >= start && j >= start+length+1){ if(data[i] > data[j]){ copy[indexCopy--] = data[i--]; count += j-start-length; }else copy[indexCopy--] = data[j--]; } while(i>=start) copy[indexCopy--] = data[i--]; while(j>=start+length+1) copy[indexCopy--] = data[j--]; return left+right+count; } };

面试题52 两个链表的第一个公共节点

输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

//首先遍历两个链表得到他们的长度,就能知道那个链表比较长,以及长的链表比短的链表多几个节点,在第二次遍历时,先在第一个链表上走若干部,接着同时在两个链表上遍历,找到的第一个相同的节点就是他们的第一个公共节点。 /* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { int length1 = GetListLength(pHead1); int length2 = GetListLength(pHead2); int lengthDif = length1-length2; ListNode* pListHeadLong = pHead1; ListNode* pListHeadShort = pHead2; if(length1<length2){ pListHeadLong = pHead2; pListHeadShort = pHead1; lengthDif = length2-length1; } for(int i=0; i<lengthDif;i++) pListHeadLong = pListHeadLong->next; while(pListHeadLong!=nullptr && pListHeadShort!=nullptr && pListHeadLong != pListHeadShort){ pListHeadLong = pListHeadLong->next; pListHeadShort = pListHeadShort->next; } return pListHeadLong; } int GetListLength(ListNode* pHead){ int length = 0; ListNode* pNode = pHead; while(pNode!=nullptr){ length++; pNode = pNode->next; } return length; } };

面试题53 在排序数组中查找数字

题目一 数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数。例如,输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4.

class Solution { public: int GetNumberOfK(vector<int> data ,int k) { int number = 0; if(data.empty()) return 0; int length = data.size(); int first = getFirstK(data, length, k, 0, length-1); int end = getEndK(data, length, k, 0, length-1); if(first>-1 && end>-1) number = end-first+1; return number; } int getFirstK(vector<int> data, int length, int k, int start, int end){//第一个k的下标 if(start > end) return -1; int middleIndex = (start+end)/2; int middleData = data[middleIndex]; if(middleData == k){ if((middleIndex>0 && data[middleIndex-1]!=k)||middleIndex==0) return middleIndex; else end = middleIndex-1; }else if(middleData>k) end = middleIndex-1; else start = middleIndex+1; return getFirstK(data, length, k, start, end); } int getEndK(vector<int> data, int length, int k, int start, int end){//最后一个k的下标 if(start > end) return -1; int middleIndex = (start+end)/2; int middleData = data[middleIndex]; if(middleData == k){ if((middleIndex<length-1 && data[middleIndex+1]!=k)||middleIndex==length-1) return middleIndex; else start = middleIndex+1; }else if(middleData>k) end = middleIndex-1; else start = middleIndex+1; return getEndK(data, length, k, start, end); } };

题目二 0~n-1中缺失的数字

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0n-1之内,在范围0n-1内的n个数组中有且只有一个数字不在该数组中,请找出这个数字。

//基于二分法的查找 int GetMissingNumber(const int* numbers, int length){ if(numbers = nullptr || length<=0) return -1; int left = 0; int right = length-1; //如果中间元素的值和下标相等,那么下一轮查找查右半边 //如果中间元素的值和下标不相等,并且它前面的一个元素和他的下标相等,则返回该值 //如果中间元素的值和下标不相等,前面的一个元素和下标也不相等,下一轮查找在左半边 while(left<=right){ int middle = (left+right) >> 1; if(numbers[middle]!=middle){ if(middle==0 ||numbers[middle-1] == middle-1) return middle; else right = middle-1; } else left = middle+1; } if(left = length) return length; return -1; }

题目三 数组中数值和下标相等的元素

假设一个单调递增的数组里的每个元素都是整数并且是唯一的,找出数组中任意一个数值等于其下标的元素,例如在数组{-3,-1,1,3,5}中,数字3和他的下标相等

int GetNumberSameAsIndex(const int* numbers, int length){ if(numbers==nullptr || length==0) return -1; int left = 0; int right = length-1; while(left <= right){ int middle = left + ((right-left)>>1); if(numbers[middle] = middle) return middle; if(numbers[middle]>middle) right = middle-1; else left = middle+1; } return -1; }

面试题54 二叉搜索树的第k大节点

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ //中序遍历二叉树,即是有序的 class Solution { public: TreeNode* KthNode(TreeNode* pRoot, int k) { if(pRoot == nullptr || k==0) return nullptr; return KthNodeCore(pRoot, k); } TreeNode* KthNodeCore(TreeNode* pRoot, int &k){ TreeNode* target = nullptr; if(pRoot->left != nullptr) //遍历左子树 target = KthNodeCore(pRoot->left, k); if(target == nullptr){ //遍历根节点 ,判断是否是target if(k==1) target = pRoot; k--; } if(target==nullptr && pRoot->right!=nullptr) //遍历右子树 target = KthNodeCore(pRoot->right, k); return target; } };

面试题55 二叉树的深度

题目一 二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: int TreeDepth(TreeNode* pRoot) { if(pRoot==nullptr) return 0; int nleft = TreeDepth(pRoot->left); int nright = TreeDepth(pRoot->right); return (nleft > nright) ? (nleft+1) : (nright+1); //左子树右子树都为空则返回1 } };

题目二 平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么他就是一颗平衡二叉树。在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树。

//后序遍历的方式遍历二叉树的每个节点,只要在遍历每个节点的时候记录他的深度(某一个节点的深度等于他到叶节点的长度) class Solution { public: bool IsBalanced_Solution(TreeNode* pRoot) { int depth = 0; return IsBalanced(pRoot, &depth); } bool IsBalanced(TreeNode* pRoot, int* depth){ if(pRoot == nullptr){ *depth = 0; return true; } int left, right; if(IsBalanced(pRoot->left, &left) && IsBalanced(pRoot->right, &right)) { int diff = left-right; if(diff<=1 && diff>=-1) //判断是否是平衡二叉树 { *depth = 1+(left>right ? left:right); return true; } } return false; } };

面试题56 数组中数字出现的次数

题目一 数组中只出现一次的两个数字

class Solution { public: void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) { if(data.empty()) return; int temp = 0; for(int i=0; i<data.size(); i++) temp ^= data[i]; int indexOf1 = FindFirstBitIs1(temp); *num1 = *num2 = 0; for(int j=0; j<data.size(); j++){ if(IsBit1(data[j], indexOf1)) //分成两组 *num1 ^= data[j]; else *num2 ^= data[j]; } } int FindFirstBitIs1(int num){ //用来在整数num的二进制表示中找到最右边是1的位 int indexBit = 0; while((num & 1) == 0){ num = num>>1; ++indexBit; } return indexBit; } bool IsBit1(int num, int indexBit){ //判断在num的二进制表示中从右边数起indexBit位是不是1 num = num >> indexBit; return (num&1); } };

题目二 数组中唯一只出现一次的数字–待看

在一个数组中除一个数字只出现一次之外,其他数字都出现了三次,请找出那个只出现一次的数字。

int FindNumberAppearingOnce(int numbers[], int length){ if(numers==nullptr || length <=0) return -1; int bitSum[32] = {0}; for(int i=0; i<length; i++){ int bitMask = 1; for(int j=31;j>=0;j--){ int bit = numbers[i]&bitMask; if(bit != 0) bitSum[j] += 1; bitMask = bitMask << 1; } } int result = 0; for(int i=0;i<32;i++){ result = result << 1; result+=bitSum[i]%3; } return result; }

面试题57 和为s的数字

题目一 和为s的两个数字

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

class Solution { public: vector<int> FindNumbersWithSum(vector<int> array,int sum) { vector<int> result; if(array.empty()) return result; int ahead = array.size()-1; int behind = 0; while(ahead > behind){ long long cursum = array[ahead] + array[behind]; if(cursum == sum){ result.push_back(array[behind]); result.push_back(array[ahead]); break; } else if(cursum > sum) ahead--; else behind++; } return result; } };

题目二 和为s的连续正数序列

输入一个正数为s,打印出所有和为s的连续正数序列。输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

class Solution { public: vector<vector<int> > FindContinuousSequence(int sum) { vector<vector<int>> result; int small=1,big=2; while(small < big){ int cursum = (small+big) * (big - small+1) / 2; if(cursum == sum){ vector<int> temp; for(int i=small; i<=big; i++) temp.push_back(i); result.push_back(temp); small++; }else if(cursum>sum) small++; else big++; } return result; } };
最新回复(0)