public class Duplication{
boolean duplication(int[] numbers,int [] num)
{
for(int i = 0;i<numbers.length;i++)
if(numbers[i]<0 || numbers[i]>numbers.length-1)
return false;
for(int j=0;j<numbers.length;j++)
{
while(numbers[j]!=j)
{
if(numbers[j]==numbers[numbers[j]])pp
{
num[0] = numbers[j];
return true;
}
int temp = numbers[j];
numbers[j] = numbers[temp];
numbers[temp]=temp;
}
}
throw new IllegalArgumentException("No such sum solution");
}
}
不修改原有数组,可以采用辅助数组的方法,此时空间复杂度是n,如果不使用额外的空间,可以使用以下的类似二分查找的方法
此算法时间复杂度是nlogn
public class getDuplication {
int duplication(int[] numbers)
{
int left = 1;
int right = numbers.length-1;
while(right >= left)
{
int middle = (right - left)/2 + left;
//二分查找midlle确定使用减的方法,如果使用加的方法会死循环
int count = countRange(numbers,left,middle);
if(right == left)
if (count > 1)
return left;
else
break;
if(count > middle-left+1)
right = middle;
else
left = middle + 1;
}
return -1;
}
int countRange(int[] a , int left ,int right )
{
if(a == null)
return -1;
int count = 0;
for(int i=0; i<a.length;i++)
if(a[i] >=left && a[i]<=right)
count ++;
return count;
}
}
采用不断矩阵右上角查找,并每次剔除一行或者一列的方法
查找到的情况放在第一个判断条件里面
public class Findum {
public int[] index(int[][] matrix,int row, int column,int target)
{
int i = 0;
int j = column-1;
while( i < row && j >= 0){
if(target == matrix[i][j])
return new int[] {i, j};
else
{
if(target > matrix[i][j])
i++;
else if(target < matrix[i][j])
j--;
}
}
throw new IllegalArgumentException("No such sum solution");
}
}
题目:替换空格,实现一个函数,把字符串中的每个空格替换成"%20"。例如,输入"we are happy.",输出"we%20are%20happy."
使用双指针,p指向原字符串组后一个元素,q指向扩充后字符串最后一个元素,逐个倒退赋值,p如果遇到空格,p往前移动一位,q进行填充,如此循环,直到p和q相等
public class Replace
{
public String ReplaceBlank(String str)
{
if(str.length()==0)
return str;
StringBuffer newstr = new StringBuffer(str);
int count = getBlankNum(str);
int p=newstr.length()-1;
for(int i=0;i<count*2;i++)
{
newstr.append("0");
}
int q=newstr.length()-1;
while(p!=q)
{
while(((Character)newstr.charAt(p)).equals(' '))
{
p--;
newstr.replace(q-2,q+1,"%20");
q=q-3;
if(p<0) return newstr.toString();
}
newstr.setCharAt(q,newstr.charAt(p));
p--;
q--;
}
return newstr.toString();
}
int getBlankNum(String str)
{
int count=0;
for(int i=0;i<str.length();i++)
{
if(str.charAt(i)==' ')
++count;
}
return count ;
}
}
采用c风格的字符数组,可以化简
申请新的数组,使用append()方法,从前往后复制,遇到空格添加%20为更简单的方法
题目:输入一个链表头节点,从尾到头反过来打印出每个节点的值
使用额外的栈来存储结点,或者使用递归
//使用栈
class ListSolution1 {
public void reverseNode(ListNode head) {
if(head.next == null)
throw new IllegalArgumentException("Don't have any listnode");
int [] myStack = new int[50];
int StackSize = -1;
ListNode p = head.next;
while (p!= null)
{
StackSize++;
myStack[StackSize] = p.val;
p=p.next;
}
while(StackSize!=-1)
System.out.println(myStack[StackSize--]);
}
}
//递归调用
class ListSolution2 {
public void reverseNode(ListNode head) {
if(head.next == null)
throw new IllegalArgumentException("Don't have any listnode");
ListNode p = head.next;
Reverse(p);
}
public void Reverse(ListNode p)
{
if(p!=null)
{
Reverse(p.next);
System.out.println(p.val);
}
}
}
题目:输入某二叉树的前序遍历和中序遍历结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
#include
#include
#include
using std::vector;
class ListSolution{
public:
TreeNode* reConstructBinaryTree(vector<int>pre,vector<int>vin)
{
if(pre.empty() && vin.empty())
return nullptr;
return Treecore(pre.begin(),pre.end(),vin.begin(),vin.end());
}
TreeNode* Treecore(vector<int>::iterator startPre,vector<int>::iterator endPre,
vector<int>::iterator startIn,vector<int>::iterator endIn)
{
int rootValue = startPre[0];
auto root = new TreeNode(rootValue);
if(startPre==endPre) {
if (startIn == endIn)
return root;
else
throw std::exception();
}
auto rootIn = startIn;
while (*rootIn != rootValue)
++rootIn;
if(rootIn > endIn)
{
throw std::exception();
}
int leftLength = rootIn - startIn;
auto leftPreEnd = startPre+leftLength;
if(leftLength>0)
{
root->left = Treecore(startPre+1,leftPreEnd,startIn,rootIn-1);
}
if(rootIn < endIn)
{
root->right = Treecore(leftPreEnd+1,endPre,rootIn+1,endIn);
}
return root;
}
};
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre == null || in == null || pre.length == 0 || in.length == 0){
return null;
}
return buildTree(pre, in, 0, pre.length - 1, 0, in.length - 1);
}
public TreeNode buildTree(int[] pre, int[] in, int preStart, int preEnd, int inStart, int inEnd){
TreeNode root = new TreeNode(pre[preStart]);
int rootIn = 0;
for(; rootIn < in.length; rootIn++){
if(in[rootIn] == root.val){
break;
}
}
int leftLength = rootIn - inStart;
int rightLength = inEnd - rootIn;
if(leftLength > 0){
root.left = buildTree(pre, in, preStart + 1, preStart + leftLength, inStart, rootIn - 1);
}
if(rightLength > 0){
root.right = buildTree(pre, in, preStart + leftLength + 1, preEnd, rootIn + 1, inEnd);
}
return root;
}
}
给定一颗二叉树和其中的一个节点,如何找出中序遍历序列的下一个节点?树中的节点除了有两个分别指向左、右节点的指针,还有一个指向父节点的指针
class solution
{
public:
TreeLinkNode* getNextNode(TreeLinkNode* pNode)
{
if(pNode == nullptr)
return nullptr;
if(pNode->right != nullptr)
{
return pNode->right;
}
if(pNode->next != nullptr && pNode->next->left == pNode)
return pNode->next;
while (pNode->next->left != pNode)
{
if(pNode->next->left == pNode)
return pNode->next;
pNode=pNode->next;
}
}
};
注意stack2为空栈的情况
public class Solution1 {
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()){
if(stack1.isEmpty())
return -1;
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
O(n)解:从下往上计算
class Solution:
def Fibonacci(self, n):
result = [0,1]
if n<2:
return result[n]
fibOne = 1
fibTwo = 0
fibN = 0
for i in range(2, n+1):
fibN = fibOne + fibTwo
fibTwo = fibOne
fibOne = fibN
return fibN
递归解(不推荐)
class Solution:
def Fibonacci(self, number):
if number < 2:
return number
if number >= 2:
return self.Fibonacci(number-1) + self.Fibonacci(number-2)
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)
class Solution:
def jumpFloor(self, number):
# write code here
mylist = [0, 1, 2, 3]
if 0 < number <= 3:
return mylist[number]
n = 4
while n <= number:
mylist.append(mylist[n-1] + mylist[n-2])
n = n + 1
return mylist[number]
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
简单的数学归纳即可解
#python版本
class Solution:
def jumpFloorII(self, number):
return 2 ** (number-1)
//java版本
//位运算
public class Solution {
public int JumpFloorII(int target) {
return 1 << (target-1);
}
}
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
归纳推理,解法与青蛙跳台阶普通版相同
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0
class Solution:
def minNumberInRotateArray(self, rotateArray):
low = 0
high = len(rotateArray) - 1
while low < high:
mid = low + (high - low) // 2
if rotateArray[mid] > rotateArray[high]:
low = mid + 1
if rotateArray[mid] == rotateArray[high]:
high = high - 1
if rotateArray[mid] < rotateArray[high]:
high = mid
return rotateArray[low]
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子.
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
if(matrix==null || matrix.length==0 || str==null || str.length==0 || matrix.length!=rows*cols || rows<=0 || cols<=0 || rows*cols < str.length) {
return false ;
}
boolean[] visited = new boolean[rows*cols] ;
int[] pathLength = {0} ;
for(int i=0 ; i<=rows-1 ; i++) {
for(int j=0 ; j<=cols-1 ; j++) {
if(hasPathCore(matrix, rows, cols, str, i, j, visited, pathLength)) { return true ; }
}
}
return false ;
}
public boolean hasPathCore(char[] matrix, int rows, int cols, char[] str, int row, int col, boolean[] visited, int[] pathLength) {
boolean flag = false ;
if(row>=0 && row<rows && col>=0 && col<cols && !visited[row*cols+col] && matrix[row*cols+col]==str[pathLength[0]]) {
pathLength[0]++ ;
visited[row*cols+col] = true ;
if(pathLength[0]==str.length) { return true ; }
flag = hasPathCore(matrix, rows, cols, str, row, col+1, visited, pathLength) ||
hasPathCore(matrix, rows, cols, str, row+1, col, visited, pathLength) ||
hasPathCore(matrix, rows, cols, str, row, col-1, visited, pathLength) ||
hasPathCore(matrix, rows, cols, str, row-1, col, visited, pathLength) ;
if(!flag) {
pathLength[0]-- ;
visited[row*cols+col] = false ;
}
}
return flag ;
}
}
class Solution{
public:
bool hasPath(vector<vector<char>>& matrix, string str){
for(int i = 0;i< matrix.size(); i++)
for(int j = 0; j< matrix[i].size();j++)
if(dfs(matrix, str,0,ij))
return true;
return false;
}
bool dfs(vector<vector<char>>& matrix,string &str,int u,int x, int y)
{
if(u == str.size())return true;
if(matrix[x][y] != str[u])return false;
int dx[4] = {-1,0,1,0}, dy = {0,1,0,-1};
char t = matrix[x][y];
matrix[x][y] = '*';
for(int i = 0; i<4;i++){
int a = x + dx[i],b = y + dy[i];
if(a >= 0 && a < matrix.size() && b >= 0 && b < matrix[a].size())
{
if(dfs(matrix,str,u + 1,a,b))return true;
}
}
matrix[x][y] = t;]
return false;
}
}
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子
#include
#include
const int MAXN=100;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0}; //四个方向
int vis[MAXN][MAXN]={0}; //记录数组
int sum; //记录结果
class Solution{
public:
void dfs(int x,int y,int k,int m,int n)
{
vis[x][y]=1;
for(int i=0;i<=3;++i)
{
int newx=x+dx[i],newy=y+dy[i];
//判断方格是否合法,合法就从该方格接着搜索
if(vis[newx][newy]==0 && newx>=0 && newy>=0 && newx<m && newy<n && (newx/10+newx%10+newy/10+newy%10 <=k ))
{
++sum;
dfs(newx,newy,k,m,n);
}
}
}
int movingCount(int threshold, int rows, int cols)
{
if(threshold<0)
return 0;
memset(vis,0, sizeof(vis));
sum=1;
dfs(0,0,threshold,rows,cols);
return sum;
}
};
class Solution
{
public:
int cutRope(int length) {
if (length < 2)
return 0;
if (length < 4)
return length - 1;
int timesOf3 = length / 3;
if (length % timesOf3 == 1) {
--timesOf3;
}
int timesOf2 = (length - timesOf3 * 3) / 2;
return (int) (pow(3, timesOf3) * pow(2, timesOf2));
}
};
思路:把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于把整数的二进制表示中最右边的1变成0。很多二进制的问题都可以使用这种思路
class Solution {
public:
int NumberOf1(int n) {
int count = 0;
while(n)
{
++count;
n = (n-1)&n;
}
return count;
}
};
普通方法只需控制好pow为负数,n为负数的情况。使用快速幂可以再logn的时间内完成
class Solution {
public:
double FastPow(int n ,int pow)
{
int res = 1;
while(n>0)
{
if(pow&1) //相当于判断pow%2==1
res*=n;
n*=n;
pow>>=1;
}
return res;
}
double Power(double base, int exponent) {
if(base==0)
return 0;
if(exponent==1)
return base;
if(exponent==0)
return 1;
if(exponent>0)
return FastPow(base,exponent);
if(exponent<0)
return 1/FastPow(base,-exponent);
}
};
使用字符串(数组)来避免大整数
为了避免代码的冗长,可以使用全排列
// 解法1,使用字符数组
public class Solution {
public void print1ToMax(int n)
{
if (n > 0)
{
char[] chars = new char[n];
for(int i = 0; i < n; ++i)
{
chars[i]='0';
}
while(increment(chars))
{
printNum(chars);
}
}
}
// 打印数字,排除掉字符数组前几位为0的情况
public void printNum(char[] number)
{
int i = 0;
while(number[i] == '0')
{
i++;
}
StringBuilder sb = new StringBuilder();
for(int j = i; j < number.length;++j)
{
sb.append(number[j]);
}
System.out.println(sb);
}
// 实现了在O(1)时内判断是不是已经达到了最大的n位数
public boolean increment(char[] chars)
{
boolean flag = true;
int carry = 1;
for(int i = chars.length - 1; i >= 0;--i)
{
int num = chars[i] - '0' + carry;
if(num>9)
{
if(i==0)
{
flag = false;
break;
}
chars[i] = '0';
}
else
{
++chars[i];
break;
}
}
return flag;
}
}
//使用全排列
//使用java会出现bug,这里使用cpp
class permutation
{
public:
void permutation_core(int n)
{
char *chars = new char[n+1];
memset(chars,'0',n);
chars[n+1]='\0';
for(int i=0;i<10;++i)
{
chars[0]=i+'0';
permutation_recursion(chars,n,0);
}
delete[] chars;
}
void permutation_recursion(char *chars,int length,int index)
{
if(index==length-1)
{
print_chars(chars,length);
return;
}
for(int i=0;i<10;++i)
{
chars[index+1]=i+'0';
permutation_recursion(chars,length,index+1);
}
}
void print_chars(char *chars,int length)
{
int i=0;
while(chars[i]=='0')
++i;
if(i==length)
return;
for(int j=i;j<length;j++)
printf("%c",chars[j]);
printf("\n");
}
};
注意题目说的是已知某节点,因此可以做到O(1)时间删除
public class Solution
{
public void deleteNode(ListNode head , ListNode p)
{
if(head == null && p == null)
return;
if(p == head.next)
{
head.next = null;
}
else if(p.next != null)
{
p.val = p.next.val;
p.next = p.next.next;
}
else
{
ListNode q = head.next;
while(q.next != p)
q = q.next;
q.next = null;
}
}
}
非递归实现
public class Solution
{
public ListNode deleteDuplication(ListNode pHead)
{
ListNode preNode = null;
ListNode curNode = pHead;
while (curNode != null)
{
if(curNode.next != null && curNode.next.val == curNode.val)
{
int val = curNode.val;
while(curNode.next !=null && curNode.next.val == val)
{
curNode = curNode.next;
}
if(preNode == null) //包括头节点在内的节点数值相同
{
pHead = curNode.next;
}
else
preNode.next = curNode.next;
}
else
{
preNode = curNode;
}
curNode = curNode.next; //循环进行条件,先写
}
return pHead;
}
}
递归实现
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplication(self, pHead):
# 只有0个或者一个节点,返回
if pHead is None or pHead.next is None:
return pHead
Node = pHead.next
# 当前节点是重复节点
if Node.val == pHead.val:
while pHead.val == Node.val and Node.next is not None:
Node = Node.next
# 如果当前节点与head节点值不同,则继续递归
if pHead.val != Node.val:
pHead = self.deleteDuplication(Node)
# 否则,包括头节点在内的所有节点的值相同
else:
return None
else:
pHead.next = self.deleteDuplication(pHead.next)
return pHead
当模式中的第二个字符是“*”时
1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。
2、如果 字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。
而当模式中的第二个字符是“*”时:
如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式:
1、模式后移2字符,相当于x*被忽略;
2、字符串后移1字符,模式后移2字符;
3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;
class Solution {
public:
bool match(char* str, char* pattern)
{
if(!str || !pattern)
return false;
if(*str=='\0' && *pattern=='\0')
return true;
if(*str!='\0' && *pattern=='\0')
return false;
if(*(pattern+1)=='*')
{
if(*pattern==*str || (*pattern=='.'&&*str!='\0'))
//move on the next state
return match(str+1,pattern+2)
//stay on the current state
|| match(str,pattern+2)
|| match(str+1,pattern);
else
//ignore a'*'
return match(str,pattern+2);
}
if(*str==*pattern||(*pattern=='.'&&*str!='\0')) //下一个不是‘*’
return match(str+1,pattern+1);
return false;
}
};
3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;
class Solution {
public:
bool match(char* str, char* pattern)
{
if(!str || !pattern)
return false;
if(*str=='\0' && *pattern=='\0')
return true;
if(*str!='\0' && *pattern=='\0')
return false;
if(*(pattern+1)=='*')
{
if(*pattern==*str || (*pattern=='.'&&*str!='\0'))
//move on the next state
return match(str+1,pattern+2)
//stay on the current state
|| match(str,pattern+2)
|| match(str+1,pattern);
else
//ignore a'*'
return match(str,pattern+2);
}
if(*str==*pattern||(*pattern=='.'&&*str!='\0')) //下一个不是‘*’
return match(str+1,pattern+1);
return false;
}
};