剑指Offer全解
二维数组中的查找
描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
源码
public class Solution {
public boolean Find(int target, int [][] array) {
if(array.length==0 || array[0].length==0){
return false;
}
int row = 0,col = 0;
for(int i=0;i<array[0].length;i++){
if(array[0][i]<target){
col = i;
}else{
break;
}
}
for(int i=0;i<array.length;i++){
if(array[i][col]<target){
row = i;
}else{
break;
}
}
for(int i=row;i<array.length;i++){
for(int k=0;k<=col;k++){
if(array[i][k]==target){
return true;
}
}
}
return false;
}
}
替换空格
描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
源码
public class Solution {
public String replaceSpace(StringBuffer str) {
int wsCnt = 0;
for(int i=0;i<str.length();i++){
if(str.charAt(i)==' '){
wsCnt++;
}
}
int oldLen = str.length();
str.setLength(wsCnt*2+str.length());
for(int i=oldLen-1;i>=0;i--){
if(str.charAt(i)!=' '){
str.setCharAt(i+wsCnt*2,str.charAt(i));
}else{
str.setCharAt(i+wsCnt*2,'0');
str.setCharAt(i+wsCnt*2-1,'2');
str.setCharAt(i+wsCnt*2-2,'%');
wsCnt--;
}
}
return str.toString();
}
}
从尾到头打印链表
描述
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
源码
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> list = new ArrayList<>();
if(listNode==null){
return list;
}
while(listNode!=null){
list.add(0,listNode.val);
listNode=listNode.next;
}
return list;
}
}
重建二叉树
描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
源码
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode subTree(int[] preOrder, int[] inOrder,
int preStart, int preEnd,
int inStart, int inEnd){
if(preStart>=preEnd){
return null;
}
// root val
TreeNode t = new TreeNode(preOrder[preStart]);
// find index of node value in inOrder array
int pos = 0;
for(int i=0;i<inOrder.length;i++){
if(inOrder[i]==preOrder[preStart]){
pos = i;
break;
}
}
// left and right
t.left = subTree(preOrder,inOrder,
preStart+1,preStart+1+(pos-inStart),
inStart,pos);
t.right = subTree(preOrder,inOrder,
preStart+1+(pos-inStart),preEnd,
pos+1,inEnd);
return t;
}
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
return subTree(pre,in,0,pre.length,0,in.length);
}
}
用两个栈实现队列
描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
源码
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if(!stack2.isEmpty()){
return stack2.pop();
}else{
while(stack1.size()!=1){
int val = stack1.pop();
stack2.push(val);
}
return stack1.pop();
}
}
}
旋转数组的最小数字
描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
源码
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length<=1){
return array.length;
}
for(int i=1;i<array.length;i++){
if(array[i]<array[0]){
return array[i];
}
}
return 0;
}
}
斐波那契数列
描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39
源码
public class Solution {
public int Fibonacci(int n) {
if(n<=1){
return n>=0?n:0;
}
int a = 0,b=1,c=1;
for(int i=2;i<=n;i++){
c = a+b;
a = b;
b = c;
}
return c;
}
}
跳台阶
描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
源码
public class Solution {
public int JumpFloor(int target) {
int a=1,b=2,c=3;
if(target<=3){
return target>0?target:0;
}
for(int i=c;i<=target;i++){
c = a + b;
a = b;
b = c;
}
return c;
}
}
变态跳台阶
描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
源码
public class Solution {
public int JumpFloorII(int target) {
return 1<<(target-1);
}
}
矩形覆盖
描述
以用2*1
的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1
的小矩形无重叠地覆盖一个2*n
的大矩形,总共有多少种方法?
源码
public class Solution {
public int RectCover(int target) {
int a=1,b=2,c=3;
if(target<=3){
return target>0?target:0;
}
for(int i=c;i<=target;i++){
c = a + b;
a = b;
b = c;
}
return c;
}
}
二进制中1的个数
描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
源码
class Solution {
public int NumberOf1(int n) {
int cnt = 0;
while(n!=0){
cnt++;
// 把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0
n = n&(n-1);
}
return cnt;
}
}
数值的整数次方
描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
源码
public class Solution {
public double Power(double base, int exponent) {
boolean flag = false;
if(exponent==0 && base!=0){
return 1.0;
}
if(base==0){
return 0;
}
double res = 1.0;
for(int i=0;i<Math.abs(exponent);i++){
res *=base;
}
return exponent>0?res:1/res;
}
}
调整数组顺序使奇数位于偶数前面
描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
源码
class Solution {
public:
void reOrderArray(vector<int> &array) {
int cnt = 0;
for(int i=0;i<array.size();i++){
if(array[i]%2==1){
int p = i;
while(p>cnt){
int t = array[p];
array[p]=array[p-1];
array[p-1]=t;
p--;
}
cnt++;
}
}
}
};
链表中倒数第k个结点
描述
输入一个链表,输出该链表中倒数第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) {
// 1-2-3-4
if(pListHead==nullptr || k==0){
return nullptr;
}
ListNode* p1=pListHead,*p2=pListHead;
int cnt = 0;
while(p2 && cnt<k){
p2 = p2->next;
cnt++;
}
if(cnt!=k){
return nullptr;
}
while(p2){
p1=p1->next;
p2=p2->next;
}
return p1;
}
};
反转链表
描述
输入一个链表,反转链表后,输出新链表的表头。
源码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead==nullptr){
return nullptr;
}
ListNode* newHead = nullptr;
while(pHead){
ListNode*t = new ListNode(pHead->val);
t->next = newHead;
newHead = t;
pHead=pHead->next;
}
return newHead;
}
};
合并两个排序的链表
描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
源码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2){
// 1->2->3->5
// 2->3->4
if(pHead1==nullptr&&pHead2!=nullptr){
return pHead2;
}else if(pHead1!=nullptr&&pHead2==nullptr){
return pHead1;
}else if(pHead1==nullptr&&pHead2==nullptr){
return nullptr;
}
ListNode* newHead = nullptr;
if(pHead1->val > pHead2->val){
newHead = pHead2;
}else{
newHead = pHead1;
}
while(pHead1!=nullptr||pHead2!=nullptr){
if(pHead1!=nullptr&&pHead2!=nullptr){
if(pHead1->val <= pHead2->val){
ListNode* cur = pHead1->next;
pHead1->next = pHead2;
pHead1 = cur;
}else{
ListNode* cur = pHead2->next;
pHead2->next = pHead1;
pHead2 = cur;
}
}
else if(pHead1!=nullptr && pHead2==nullptr){
pHead1 = pHead1->next;
}
else if(pHead2!=nullptr && pHead1==nullptr){
pHead2 = pHead2->next;
}
}
return newHead;
}
};
树的子结构
描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
源码
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public boolean check(TreeNode a, TreeNode b){
if(b==null){
return true;
}
if(a==null){
return false;
}
if(a.val==b.val){
return check(a.left,b.left)&&check(a.right,b.right);
}
return false;
}
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if(root1 == null || root2 == null){
return false;
}
if(root1.val==root2.val){
boolean r = check(root1,root2);
if(r){
return true;
}
}
boolean res= HasSubtree(root1.left,root2);
if(res){
return true;
}
res = HasSubtree(root1.right,root2);
if(res){
return true;
}
return false;
}
}
二叉树的镜像
描述
操作给定的二叉树,将其变换为源二叉树的镜像。
源码
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public void Mirror(TreeNode root) {
if(root==null){
return;
}
TreeNode a = root.left;
root.left = root.right;
root.right = a;
Mirror(root.left);
Mirror(root.right);
}
}
顺时针打印矩阵
描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
源码
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
vector<int> v;
if(matrix.size()==0||matrix[0].size()==0){
return v;
}
int i=0,j=0;
int cnt = 0;
int widthStart = 0;
int widthEnd = matrix[0].size();
int heightStart = 0;
int heightEnd = matrix.size();
while(cnt < matrix.size()*matrix[0].size()){
while(j<widthEnd){
v.push_back(matrix[i][j]);
j++;
cnt++;
}
j--;
i++;
if(i>=heightEnd){
break;
}
while(i<heightEnd){
v.push_back(matrix[i][j]);
i++;
cnt++;
}
i--;
j--;
if(j<widthStart){
break;
}
while(j>=widthStart){
v.push_back(matrix[i][j]);
j--;
cnt++;
}
j++;
i--;
if(i<heightStart){
break;
}
while(i>=heightStart+1){
v.push_back(matrix[i][j]);
i--;
cnt++;
}
i++;
j++;
widthEnd--;
widthStart++;
heightStart++;
heightEnd--;
}
return v;
}
};
包含min函数的栈
描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))
源码
class Solution {
public:
stack<int> s;
stack<int> aux;
void push(int value) {
s.push(value);
if(!aux.empty()){
int t = aux.top();
if(t>value){
aux.push(value);
}else{
aux.push(t);
}
}else{
aux.push(value);
}
}
void pop() {
s.pop();
aux.pop();
}
int top() {
return aux.top();
}
int min() {
return aux.top();
}
};
栈的压入、弹出序列
描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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) {
if(pushV.empty() || popV.empty()){
return false;
}
int start = 0;
int cnt =0;
stack<int> s;
while(cnt<popV.size()){
int p = popV[cnt];
if(!s.empty() && s.top()==p){
s.pop();
}else{
for(;start<pushV.size();start++){
s.push(pushV[start]);
if(pushV[start]==p){
start++;
break;
}
}
if(s.top()==p){
s.pop();
}else{
return false;
}
}
cnt++;
}
return true;
}
};
从上往下打印二叉树
描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
源码
/*
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> vec;
if(root==nullptr){
return vec;
}
deque<TreeNode*> q;
q.push_back(root);
while(!q.empty()){
auto tmp = q.front();
q.pop_front();
vec.push_back(tmp->val);
if(tmp->left){
q.push_back(tmp->left);
}
if(tmp->right){
q.push_back(tmp->right);
}
}
return vec;
}
};
二叉搜索树的后序遍历序列
描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
源码
class Solution {
public:
bool check(const vector<int>&seq,int start,int end){
if(start>=end){
return true;
}
int root = seq[end-1];
int right = start;
for(;right<end;right++){
if(seq[right]>root){
break;
}
}
for(int t=right;t<end;t++){
if(seq[t]<root){
return false;
}
}
return check(seq,start,right-1)&&check(seq,right,end-1);
}
bool VerifySquenceOfBST(vector<int> sequence) {
if(sequence.size()==0){
return false;
}
if(sequence.size()==1){
return true;
}
return check(sequence,0,sequence.size());
}
};
二叉树中和为某一值的路径
描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
源码
/*
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>> paths;
vector<int> temp;
void dfs(TreeNode* root, int target){
if(target-root->val==0 && root->left==nullptr && root->right==nullptr){
temp.push_back(root->val);
paths.push_back(temp);
temp.pop_back();
return;
}
if(root->left){
temp.push_back(root->val);
dfs(root->left,target- root->val);
temp.pop_back();
}
if(root->right){
temp.push_back(root->val);
dfs(root->right,target- root->val);
temp.pop_back();
}
}
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
if(root==nullptr){
return paths;
}
dfs(root,expectNumber);
return paths;
}
};
复杂链表的复制
描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
源码
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* seqClone(RandomListNode* pHead){
RandomListNode* head = new RandomListNode(pHead->label);
head->random = pHead->random;
pHead=pHead->next;
RandomListNode* copied =head;
while(pHead){
RandomListNode*temp = new RandomListNode(pHead->label);
temp->random = pHead->random;
head->next = temp;
head = head->next;
pHead=pHead->next;
}
return copied;
}
int getPos(RandomListNode * head,RandomListNode* target){
int i=0;
do{
if(target==head){
return i;
}
head=head->next;
i++;
}while(head);
return i;
}
RandomListNode* getNode(RandomListNode* head,int i){
int s=0;
while(s<i){
head=head->next;
s++;
}
return head;
}
RandomListNode* Clone(RandomListNode* pHead){
if(pHead==nullptr){
return nullptr;
}
RandomListNode* copied = seqClone(pHead);
RandomListNode* t = copied;
while(t){
int pos = getPos(pHead,t->random);
t->random = getNode(copied,pos);
t=t->next;
}
return copied;
}
};
二叉搜索树与双向链表
描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
源码
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void listify(TreeNode* cur, TreeNode*& pre){
if(cur==nullptr){
return;
}
listify(cur->left,pre);
cur->left = pre;
if(pre){
pre->right = cur;
}
pre = cur;
listify(cur->right,pre);
}
TreeNode* Convert(TreeNode* pRootOfTree){
TreeNode* r = pRootOfTree;
if(r!=nullptr){
TreeNode* pre = nullptr;
listify(r,pre);
while(r->left){
r = r->left;
}
return r;
}
return r;
}
};
字符串的排列
描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
源码
class Solution {
public:
set<string> all;
void dfs(string str,string a,vector<char> chars){
if(a.length()==str.length()){
all.insert(a);
return;
}
for(int i=0;i<chars.size();i++){
if(chars[i]!='\0'){
char c = chars[i];
chars[i]='\0';
dfs(str,a+c,chars);
chars[i] = c;
}
}
}
vector<string> Permutation(string str) {
if(str.length()==0){
return vector<string>();
}
vector<char> c;
for(char val:str){
c.push_back(val);
}
dfs(str,"",c);
vector<string> res;
for(const string &s:all){
res.push_back(s);
}
return res;
}
};
数组中出现次数超过一半的数字
描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
源码
class Solution {
public:
int partition(vector<int> & arr, int left, int right){
int i = left;
int j = right;
int pivot = arr[left];
while(i<j){
while(i<j && arr[j]>pivot) j--;
if(i<j) arr[i++] = arr[j];
while(i<j && arr[i]<pivot) i++;
if(i<j) arr[j--] = arr[i];
}
arr[i] = pivot;
return i;
}
int MoreThanHalfNum_Solution(vector<int> numbers) {
int start=0,end = numbers.size()-1;
int index = partition(numbers,0,end);
while(index!=numbers.size()/2){
if(index>numbers.size()/2){
end = index -1;
index = partition(numbers,start,end);
}else{
start = index+1;
index = partition(numbers,start,end);
}
}
int cnt = 0;
for(int i=0;i<numbers.size();i++){
if(numbers[i]==numbers[index]){
cnt++;
}
}
return cnt>index?numbers[index]:0;
}
};
最小的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) {
if(input.size()==0||k<=0 || input.size()<k){
return vector<int>();
}
vector<int> v;
make_heap(input.begin(),input.end(),greater<int>());
for(int i=0;i<k;i++){
pop_heap(input.begin(),input.end(),greater<int>());
v.push_back(input[input.size()-1]);
input.pop_back();
}
return v;
}
};
连续子数组的最大和
描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
class Solution {
public:
int dp[1000]={0};
int FindGreatestSumOfSubArray(vector<int> array) {
if(array.size()==0){
return 0;
}
for(int i=0;i<array.size();i++){
dp[i+1] = dp[i]>0?array[i]+dp[i]:array[i];
}
int m=INT_MIN;
for(int i=1;i<=array.size();i++){
if(dp[i]>m){
m=dp[i];
}
}
return m;
}
};
把数组排成最小的数
描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
class Solution {
public:
static int cmp(int a,int b){
string str1,str2;
str1+=to_string(a);
str1+=to_string(b);
str2+=to_string(b);
str2+=to_string(a);
return str1<str2;
}
string PrintMinNumber(vector<int> numbers) {
sort(numbers.begin(),numbers.end(),cmp);
string result;
for(int i:numbers){
result+=to_string(i);
}
return result;
}
};
丑数
描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
源码
class Solution {
public:
int findMin(int a,int b,int c){
int t = (a>b?b:a);
return (t>c?c:t);
}
int GetUglyNumber_Solution(int index){
if(index<=1){
return index;
}
int p2=0,p3=0,p5=0;
vector<int> v;
v.push_back(1);
while(v.size()<index){
int min = findMin(v[p2]*2,v[p3]*3,v[p5]*5);
if(v[p2]*2==min)p2++;
if(v[p3]*3==min)p3++;
if(v[p5]*5==min)p5++;
v.push_back(min);
}
return v[v.size()-1];
}
};
第一个只出现一次的字符
描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
源码
class Solution {
public:
int FirstNotRepeatingChar(string str) {
map<char,int> m;
for(int i=0;i<str.length();i++){
m[str[i]]++;
}
for(int i=0;i<str.length();i++){
if(m[str[i]]==1){
return i;
}
}
return -1;
}
};
数组中的逆序对
描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
源码
class Solution {
public:
int cnt;
void divide(vector<int> &arr,int start, int end){
if(start>=end){
return;
}
int mid = (start+end)>>1;
divide(arr,start,mid);
divide(arr,mid+1,end);
merge(arr,start,mid,end);
}
void merge(vector<int> &arr,int start, int mid, int end){
int* aux = new int[end-start+1];
int i=start,j=mid+1,k=0;
while(i<=mid && j<= end){
if(arr[i]<=arr[j]){
aux[k++]=arr[i++];
}else{
aux[k++]=arr[j++];
cnt += (mid-i+1);
cnt %= 1000000007;
}
}
while(i<=mid){
aux[k++]=arr[i++];
}
while(j<=end){
aux[k++]=arr[j++];
}
for(int i=0;i<end-start+1;i++){
arr[start+i]=aux[i];
}
delete[]aux;
}
int InversePairs(vector<int> data) {
cnt=0;
if(data.size()==0){
return cnt;
}
divide(data,0,data.size()-1);
return cnt;
}
};
两个链表的第一个公共结点
描述
输入两个链表,找出它们的第一个公共结点。
源码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
if(pHead1==nullptr||pHead2==nullptr){
return nullptr;
}
stack<ListNode*> a,b;
ListNode* t1=pHead1,*t2=pHead2;
while(t1){
a.push(t1);
t1=t1->next;
}
while(t2){
b.push(t2);
t2=t2->next;
}
while(!a.empty()&&!b.empty()){
t1=a.top();
t2=b.top();
if(t1!=t2){
return t1->next;
}
a.pop();
b.pop();
}
if(a.empty()&&!b.empty()){
return b.top()->next;
}else if(b.empty()&&!a.empty()){
return a.top()->next;
}else{
return pHead1;
}
}
};
数字在排序数组中出现的次数
描述
统计一个数字在排序数组中出现的次数。
源码
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
auto pos = find(data.begin(),data.end(),k);
if(pos==data.end()){
return 0;
}
int cnt=0;
while(true){
if(*pos==k){
cnt++;
}else{
break;
}
pos++;
}
return cnt;
}
};
二叉树的深度
描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
源码
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
int max = 0;
void dfs(TreeNode* node,int depth){
if(!node){
if(depth>max){
max = depth;
}
return;
}
dfs(node->left,depth+1);
dfs(node->right,depth+1);
}
int TreeDepth(TreeNode* pRoot){
if(pRoot==nullptr){
return 0;
}
dfs(pRoot,0);
return max;
}
};
平衡二叉树
描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
源码
class Solution {
public:
bool isBalanced=true;
int dfs(TreeNode* node){
if(!node){
return 0;
}
int a = dfs(node->left);
int b = dfs(node->right);
if(abs(a-b)>1){
isBalanced=false;
}
return a>b?a+1:b+1;
}
bool IsBalanced_Solution(TreeNode* pRoot) {
if(pRoot==nullptr){
return true;
}
dfs(pRoot);
return isBalanced;
}
};
数组中只出现一次的数字
描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
源码
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
map<int,int> m;
for(int i:data){
m[i]++;
}
bool first = true;
for(auto v:m){
if(v.second==1){
if(first){
*num1 = v.first;
first=false;
}else{
*num2=v.first;
}
}
}
}
};
和为S的连续正数序列
描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9-16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?Good Luck
源码
class Solution {
public:
int calcSum(int start, int end){
return (start+end)*(end-start+1)/2;
}
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int>> res;
int start = 1;
int end = 2;
while(start<end){
if(calcSum(start,end)<sum){
end++;
}else if(calcSum(start,end)>sum){
start++;
}else{
vector<int> v;
for(int i=start;i<=end;i++){
v.push_back(i);
}
res.push_back(v);
start++; // or end++;
}
}
return res;
}
};
和为S的两个数字
描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
源码
class Solution {
public:
vector<int> FindNumbersWithSum(vector<int> array,int sum) {
int i=0;
for(;i<array.size();i++){
if(array[i]>=sum){
break;
}
}
vector<int> v;
int start = 0;
int end = (i==array.size())?i-1:i;
while(start<end){
if(array[start]+array[end]==sum){
v.push_back(array[start]);
v.push_back(array[end]);
return v;
}else if(array[start]+array[end]>sum){
end--;
}else if(array[start]+array[end]<sum){
start++;
}
}
return v;
}
};
左旋转字符串
描述
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
源码
class Solution {
public:
string LeftRotateString(string str, int n) {
string s;
for(int i=n;i<str.length();i++){
s+=str[i];
}
for(int i=0;i<n;i++){
s+=str[i];
}
return s;
}
};
翻转单词顺序列
描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
源码
class Solution {
public:
void bitwise_reverse(string &str){
int cnt=0;
int last = 0;
while(cnt<=str.length()){
if(cnt==str.length() || str[cnt]==' '){
int left=last,right=cnt-1;
while(left<right){
char tmp = str[left];
str[left] = str[right];
str[right] = tmp;
left++;
right--;
}
last = cnt+1;
}
cnt++;
}
}
string ReverseSentence(string str) {
bitwise_reverse(str);
for(int i=0,j=str.length()-1;i<j;i++,j--){
char tmp = str[i];
str[i]=str[j];
str[j]=tmp;
}
return str;
}
};
孩子们的游戏(圆圈中最后剩下的数)
描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
源码
class Solution {
public:
// https://blog.csdn.net/byn12345/article/details/79487253
int LastRemaining_Solution(int n, int m){
if(n==0){
return -1;
}
int cur=0;
for(int i=2;i<=n;i++){
cur = (cur+m)%i;
}
return cur;
}
};
求1+2+3+...+n
描述
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
源码
class Solution {
public:
int Sum_Solution(int n) {
return (int)(n+std::pow(n,2))>>1;
}
};
不用加减乘除做加法
描述
写一个函数,求两个整数之和,要求在函数体内不得使用+,-,*,/
四则运算符号
源码
class Solution {
public:
int Add(int num1, int num2){
return std::plus<>{}(num1,num2);
}
};
把字符串转换成整数
描述
将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。
源码
class Solution {
public:
int StrToInt(string str) {
if(str.length()==0){
return 0;
}
int start = 0;
if(str[0]=='+'|| str[0]=='-'){
start=1;
}
int res = 0;
for(int i=start;i<str.length();i++){
if(str[i]<'0'||str[i]>'9'){
return false;
}else{
res = res*10 + (str[i]-'0');
}
}
return str[0]=='-'?-res:res;
}
};
数组中重复的数字
描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
源码
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
if(numbers==nullptr||length<=0){
return false;
}
for(int i=0;i<length;i++){
if(numbers[i]<0|| numbers[i]>length-1){
return false;
}
}
for(int i=0;i<length;i++){
while(numbers[i]!=i){
if(numbers[i]!=numbers[numbers[i]]){
std::swap(numbers[i],numbers[numbers[i]]);
}else{
*duplication=numbers[i];
return true;
}
}
}
return false;
}
};
构建乘积数组
描述
给定一个数组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]。不能使用除法。
源码
class Solution {
public:
vector<int> multiply(const vector<int>& A) {
vector<int> b(A.size());
if(A.size()==0){
return b;
}
b[0]=1;
for(int i=1;i<A.size();i++){
b[i] = b[i-1]*A[i-1];
}
int t = 1;
for(int i=A.size()-2;i>=0;i--){
t = t*A[i+1];
b[i] *= t;
}
return b;
}
};
正则表达式匹配
描述
请实现一个函数用来匹配包括'.'
和'*'
的正则表达式。模式中的字符'.'表示任意一个字符,而'*'
表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"
匹配,但是与"aa.a"
和"ab*a"
均不匹配
源码
class Solution {
public:
bool matchImpl(char* str, char* pattern){
if(*str!='\0' && *pattern=='\0'){
return false;
}
if(*pattern=='\0' && *str=='\0'){
return true;
}
// 如果是重复匹配
if(*(pattern+1)=='*'){
if(*str==*pattern || *pattern=='.' && *str!='\0'){
return matchImpl(str+1,pattern+2)||
matchImpl(str+1,pattern)||
matchImpl(str,pattern+2);
}else{
return matchImpl(str,pattern+2);
}
}
// 如果是任意匹配
if(*pattern=='.'&&*str!='\0'){
return matchImpl(str+1,pattern+1);
}
// 如果是普通字符和数字
if(*pattern==*str){
return matchImpl(str+1,pattern+1);
} else{
return false;
}
}
bool match(char* str, char* pattern){
if(str==nullptr||pattern==nullptr)
return false;
return matchImpl(str,pattern);
}
};
表示数值的字符串
描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
源码
class Solution {
public:
bool modeDecimal(char* string){
while(*string){
if(*string=='e'||*string=='E'){
string++;
return modeScientific(string);
}
if(*string<'0'||*string>'9' ){
return false;
}
string++;
}
return true;
}
bool modeScientific(char *string){
// e后部分
if(*string=='+'||*string=='-'){
string++;
}
// e后至少一个数
if(*string=='\0'){
return false;
}
while(*string){
if(*string<'0'||*string>'9' ){
return false;
}
string++;
}
return true;
}
bool isNumeric(char* string){
if(string==nullptr){
return false;
}
bool isDigit = true;
if(*string=='+'||*string=='-'){
string++;
}
// 整数部分
while(*string){
if(*string=='.'){
string++;
return modeDecimal(string);
}
if(*string=='e'||*string=='E'){
string++;
return modeScientific(string);
}
if(*string<'0'||*string>'9'){
return false;
}
string++;
}
return true;
}
};
字符流中第一个不重复的字符
描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
源码
class Solution
{
public:
string sub;
map<char,int> m;
//Insert one char from stringstream
void Insert(char ch){
m[ch]++;
sub+=ch;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce(){
for(int i=0;i<sub.length();i++){
if(m[sub[i]]==1){
return sub[i];
}
}
return '#';
}
};
链表中环的入口结点
描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
源码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* jointPoint(ListNode* pHead){
ListNode* slow = pHead->next;
ListNode* fast = slow->next;
while(fast!=nullptr && slow!=nullptr){
if(fast==slow){
return fast;
}
slow = slow->next;
fast =fast ->next;
if(fast!=nullptr){
fast = fast->next;
}else{
return nullptr;
}
}
return nullptr;
}
ListNode* EntryNodeOfLoop(ListNode* pHead){
// 两个节点无法组成换
if(pHead==nullptr || pHead->next->next==nullptr){
return nullptr;
}
// 确认有环
ListNode* join = jointPoint(pHead);
if(!join){
return nullptr;
}
// 找到环的节点数
int cnt = 1;
ListNode* circleStart = join->next;
while(circleStart!=join){
circleStart=circleStart->next;
cnt++;
}
// 找到入口
ListNode* slow = pHead;
ListNode* fast = pHead;
for(int i=0;i<cnt;i++){
fast=fast->next;
}
while(slow!=fast){
slow=slow->next;
fast=fast->next;
}
return slow;
}
};
删除链表中重复的结点
描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
源码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
bool hasDuplicatedSeq(ListNode* pHead){
if(pHead->next && pHead->next->next &&
pHead->next->val == pHead->next->next->val){
return true;
}
return false;
}
ListNode* removeDuplicatedSeq(ListNode* pHead){
ListNode* current = pHead;
ListNode* duplicatedTail = nullptr;
// 删除重复序列
while(true){
if(current->next &&
current->val==current->next->val){
ListNode* tmp = current;
current = current->next;
delete tmp;
continue;
}
break;
}
duplicatedTail = current->next;
delete current;
return duplicatedTail;
}
ListNode* deleteDuplication(ListNode* pHead){
if(pHead==nullptr){
return nullptr;
}
ListNode* newHead = new ListNode(-1);
newHead->next = pHead;
ListNode* reservedNewHead = newHead;
while(newHead){
// 如果发现有重复的元素序列
if(hasDuplicatedSeq(newHead)){
// 删除重复序列
ListNode* duplicatedTail = removeDuplicatedSeq(newHead->next);
// 调整链表的链
newHead->next = duplicatedTail;
// 注意这里用conitnue而不是继续是因为有可能由于两个连续
// 的重复序列: 1->2->3->3->4->4->5
continue;
}
newHead = newHead->next;
}
return reservedNewHead->next;
}
};
二叉树的下一个结点
描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
源码
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode==null){
return null;
}
if(pNode.right!=null){
TreeLinkNode temp = pNode.right;
while(temp.left!=null && temp.right!=null){
temp = temp.left;
}
return temp;
}else if(pNode.right ==null){
if(pNode.next!=null){
// 如果父节点不为空,且当前节点是父节点的左节点
if(pNode.next.left==pNode){
return pNode.next;
}else{
// 如果父节点不为空,且当前节点是父节点的右节点
TreeLinkNode t = pNode;
while(t.next!=null && t.next.left!=t){
t=t.next;
}
return t.next;
}
}else{
return null;
}
}else{
return null;
}
}
}
对称的二叉树
描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
源码
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean check(TreeNode a,TreeNode b){
if(a==null||b==null)
return a==b?true:false;
if(a.val==b.val){
return check(a.left,b.right)&&check(a.right,b.left);
}else{
return false;
}
}
boolean isSymmetrical(TreeNode pRoot){
if(pRoot==null){
return true;
}
return check(pRoot.left,pRoot.right);
}
}
按之字形顺序打印二叉树
描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
源码
/*
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> > Print(TreeNode* pRoot) {
vector<vector<int> > res;
if(pRoot==nullptr){
return res;
}
stack<TreeNode*> sk1,sk2;
sk1.push(pRoot);
while(!sk1.empty() || !sk2.empty()){
vector<int> v;
if(!sk1.empty()){
while(!sk1.empty()){
TreeNode *t = sk1.top();
v.push_back(t->val);
sk1.pop();
if(t->left)sk2.push(t->left);
if(t->right)sk2.push(t->right);
}
}else{
while(!sk2.empty()){
TreeNode*t = sk2.top();
v.push_back(t->val);
sk2.pop();
if(t->right)sk1.push(t->right);
if(t->left)sk1.push(t->left);
}
}
res.push_back(v);
}
return res;
}
};
把二叉树打印成多行
描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
源码
/*
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> > Print(TreeNode* pRoot) {
vector<vector<int>> vec;
if(pRoot==nullptr){
return vec;
}
deque<TreeNode*> q;
q.push_back(pRoot);
q.push_back(nullptr);
while(!q.empty() && q.front()!=nullptr){
auto r = q.front();
q.pop_front();
vector<int> v;
while(r!=nullptr){
v.push_back(r->val);
if(r->left){
q.push_back(r->left);
}
if(r->right){
q.push_back(r->right);
}
r=q.front();
q.pop_front();
}
vec.push_back(v);
q.push_back(nullptr);;
}
return vec;
}
};
二叉搜索树的第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:
int cnt = 0;
TreeNode* result=nullptr;
void traverse(TreeNode* t,int target){
if(t){
traverse(t->left,target);
cnt++;
if(cnt==target){
result = t;
return;
}
traverse(t->right,target);
}
}
TreeNode* KthNode(TreeNode* pRoot, int k){
if(k==0||pRoot==nullptr){
return nullptr;
}
traverse(pRoot,k);
return result;
}
};
数据流中的中位数
描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
源码
class Solution {
public:
priority_queue<int, vector<int>, less<int> > max;
priority_queue<int, vector<int>, greater<int> > min;
int cnt=0;
void Insert(int num){
if(cnt%2){
max.push(num);
min.push(max.top());
max.pop();
}else{
min.push(num);
max.push(min.top());
min.pop();
}
cnt++;
}
double GetMedian(){
return cnt%2!=0?max.top():(max.top()+min.top())/2.0;
}
};
滑动窗口的最大值
描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
源码
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size){
vector<int> vec;
if(num.size()<size || size==0){
return vec;
}
deque<int> q;
for(int i=0;i<num.size();i++){
while(!q.empty() && num[q.back()]<=num[i]){
q.pop_back();
}
while(!q.empty() && i-q.front()+1>size){
q.pop_front();
}
q.push_back(i);
if(i+1>=size){
vec.push_back(num[q.front()]);
}
}
return vec;
}
};
矩阵中的路径
描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
源码
class Solution {
public:
bool correctPath(char* matrix, int rows, int cols, char* str,
int i, int k,int *visited, int step){
if(i<0 || k<0 || i>=rows || k>= cols){
return false;
}
if(visited[i*cols+k] ||
str[step]!=matrix[i*cols+k]){
return false;
}
if(step == strlen(str)-1){
return true;
}
visited[i*cols+k] = true;
if(correctPath(matrix,rows,cols,str,i,k+1,visited,step+1)||
correctPath(matrix,rows,cols,str,i,k-1,visited,step+1)||
correctPath(matrix,rows,cols,str,i-1,k,visited,step+1)||
correctPath(matrix,rows,cols,str,i+1,k,visited,step+1)){
return true;
}
visited[i*cols+k]=false;
return false;
}
bool hasPath(char* matrix, int rows, int cols, char* str){
int * visited = new int[rows*cols];
memset(visited,0,sizeof(int)*rows*cols);
for(int i=0;i<rows;i++){
for(int k=0;k<cols;k++){
if(correctPath(matrix,rows,cols,str,i,k,visited,0)){
delete visited;
return true;
}
}
}
delete visited;
return false;
}
};
机器人的运动范围
描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
源码
int visited[100][100];
class Solution {
public:
int sumDigit(int num){
int res = 0;
while(num){
res += (num%10);
num /= 10;
}
return res;
}
int dfs(int rows, int cols, int i,int k,int threshold){
if(i<0 || k <0 || i>=rows || k>=cols || visited[i][k]){
return 0;
}
if(sumDigit(i)+sumDigit(k)>threshold){
return 0;
}
visited[i][k]=true;
int a = 1 + dfs(rows,cols,i,k+1,threshold)
+ dfs(rows,cols,i,k-1,threshold)
+ dfs(rows,cols,i-1,k,threshold)
+ dfs(rows,cols,i+1,k,threshold);
return a;
}
int movingCount(int threshold, int rows, int cols){
int max=0;
memset(visited,0,10000*sizeof(int));
return dfs(rows,cols,0,0,threshold);
}
};
剑指Offer全解的更多相关文章
- 剑指Offer——回溯算法解迷宫问题(java版)
剑指Offer--回溯算法解迷宫问题(java版) 以一个M×N的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍.设计程序,对任意设定的迷宫,求出从入口到出口的所有通路. 下面我们来详细讲一 ...
- 《剑指offer》全部题目-含Java实现
1.二维数组中的查找 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. publi ...
- 剑指Offer——知识点储备-常用算法
剑指Offer--知识点储备-常用算法 快速排序 注:若排序是有序的,采用快排,则退化为冒泡排序. 解决这个问题,采用两个选取基准的方法 (1)随机选取基数(在这个区间内随机取一个数) 出现的恶劣情况 ...
- 剑指offer题目java实现
Problem2:实现Singleton模式 题目描述:设计一个类,我们只能生成该类的一个实例 package Problem2; public class SingletonClass { /* * ...
- 《剑指offer》内容总结
(1)剑指Offer——Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是统计和排序大量的字符串(但不仅限于字符串),所以经常 ...
- 《剑指offer》面试题32----从1到n整数中1出现的次数
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如输入12,从1到12这些整数中包含1的数字有1,10,11和12,1一共出现了5次. 解法一:不考虑时间效率的解法(略) ps ...
- 剑指offer算法总结
剑指offer算法学习总结 节选剑指offer比较经典和巧妙的一些题目,以便复习使用.一部分题目给出了完整代码,一部分题目比较简单直接给出思路.但是不保证我说的思路都是正确的,个人对算法也不是特别在行 ...
- 【剑指offer】字符串的组合
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/mmc_maodun/article/details/26405471 转载请注明出处:http:// ...
- 《剑指offer 第二版》题解
剑指Offer 按题号排序 面试题 3:数组中重复的数字 面试题 4:二维数组中的查找 面试题 5:替换空格 面试题 6:从头到尾打印链表 面试题 7:重建二叉树 面试题 8:二叉树的下一个节点 面试 ...
随机推荐
- UGUI中粒子特效与UI的遮挡问题
问题背景: 在做主线任务时发现完成任务后的特效显示穿透上面的UI层,不美观,策划不乐意了,抓紧解决下 解决思路: 首先讲下影响渲染顺序的因素: 能够影响渲染顺序的因素有:1.Camera Depth ...
- C# .net 填充无效,无法被移除 微信小程序解密失败的解决办法
微信小程序获取用户信息诸如unionId的时候需要解密,如果遇到偶然的解密失败(填充无效,无法被移除),原因很有可能是session_key错误, 也是就你用作解密的session_key并不是微信用 ...
- pip 源
pip使用过程中的痛苦,大家相必都已经知道了,目前豆瓣提供了国内的pypi源,源包相对会略有延迟,但不影响基本使用. pip install some-package -i https://pypi. ...
- java web项目部署到tomcat 8.5 此驱动程序不支持 Java Runtime Environment (JRE) 1.8 版。请使用支持 JDBC 4.0 的 sqljdbc4.jar 类库
1:项目使用的是jre1.8版本. 2:服务器 apache-tomcat-8.5.23 报错如下: 严重 [com.mchange.v2.async.ThreadPoolAsynchronousRu ...
- Angular结构型指令,模块和样式
结构型指令 *是一个语法糖,<a *ngIf="user.login">退出</a>相当于 <ng-template [ngIf]="use ...
- BZOJ2759 一个动态树好题 LCT
题解: 的确是动态树好题 首先由于每个点只有一个出边 这个图构成了基环内向树 我们观察那个同余方程组 一旦形成环的话我们就能知道环上点以及能连向环上点的值是多少了 所以我们只需要用一种结构来维护两个不 ...
- 搭建 eclipse,maven,tomcat 环境
1,安装jdk 2,安装eclipse,可以写java程序 3,安装tomcat,可以写简单的web页面 4,安装maven,再eclipse中可以构建maven管理的java程序 5,将maven程 ...
- swagger结合dubbo的rest服务测试
swagger结合dubbo的rest服务测试 背景介绍 我们应用的dubbo服务导出,可能没有直接的触发点去发起调用测试,除非自己手写controller和test类,缺乏一个动态工具,类似流行的s ...
- git 相关学习
1.Git 的一些快捷键 第一次创建本git 本地仓库 :: git init //在本地创建一个 Git仓库 :要在该目录下 第一次 要配置GitHub 的 账号和邮箱: git config ...
- 指针*p,p,&p等辨别
#include<iostream> #include<iomanip> #include<cmath> using namespace std; int main ...