二叉搜索树的第k个结点
给定一棵二叉搜索树,请找出其中的第k小的结点。
public class Solution {
int index = 0;
TreeNode KthNode(TreeNode pRoot, int k)
{
if(pRoot != null){
TreeNode node = KthNode(pRoot.left,k);
if(node != null){
return node;
}
index++;
if(k == index){
return pRoot;
}
node = KthNode(pRoot.right,k);
if(node != null){
return node;
}
}
return null;
}
}
class Solution {
public:
void inorder(TreeNode* root,TreeNode* &ans){
if(root){
inorder(root->left,ans);
count--;
if(!count) ans = root;
inorder(root->right,ans);
}
}
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if(!pRoot || k < 1) return NULL;
TreeNode* ans = NULL;
count = k;
inorder(pRoot,ans);
return ans;
}
private:
int count;
};
数据流的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
//小顶堆
private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
//大顶堆
private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
//记录偶数个还是奇数个
int count = 0;
//每次插入小顶堆的是当前大顶堆中最大的数
//每次插入大顶堆的是当前小顶堆中最小的数
//这样保证小顶堆中的数永远大于等于大顶堆中的数
//中位数就可以方便地从两者的根结点中获取了
public void Insert(Integer num) {
//个数为偶数的话,则先插入到大顶堆,然后将大顶堆中最大的数插入小顶堆中
if(count % 2 == 0){
maxHeap.offer(num);
int max = maxHeap.poll();
minHeap.offer(max);
}else{
//个数为奇数的话,则先插入到小顶堆,然后将小顶堆中最小的数插入大顶堆中
minHeap.offer(num);
int min = minHeap.poll();
maxHeap.offer(min);
}
count++;
}
public Double GetMedian() {
//当前为偶数个,则取小顶堆和大顶堆的堆顶元素求平均
if(count % 2 == 0){
return new Double(minHeap.peek() + maxHeap.peek())/2;
}else{
//当前为奇数个,则直接从小顶堆中取元素即可
return new Double(minHeap.peek());
}
}
}
// import java.util.*;
// public class Solution {
// public ArrayList<Integer> cache=new ArrayList<>();
// public int len=0;
// public int mid_1=0;
// public void Insert(Integer num) {
// if(len==0){
// cache.add(num);
// }
// else{
// int i=mid_1;
// if(num>cache.get(mid_1)){
// while(i<len && num>cache.get(i)){
// i++;
// }
// cache.add(i,num);
// if(len%2==0){
// mid_1++;
// }
// }else{
// while(i>=0 && num<=cache.get(i)){
// i--;
// }
// cache.add(i+1,num);
// if(len%2==0){mid_1++;}
// }
// }
// len++;
// }
// public Double GetMedian() {
// if(len%2==1){
// return cache.get(mid_1)/1.0;
// }
// else{
// return (cache.get(mid_1)+cache.get(mid_1+1))/2.0;
// }
// }
// }
class Solution {
private:
vector<int> min;
vector<int> max;
public:
void Insert(int num)
{
if(((min.size()+max.size())&1)==0)//偶数时 ,放入最小堆
{
if(max.size()>0 && num<max[0])
{
// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
max.push_back(num);//先将元素压入容器
push_heap(max.begin(),max.end(),less<int>());//调整最大堆
num=max[0];//取出最大堆的最大值
//pop_heap(_First, _Last),要先调用pop_heap()再在容器中删除数据
pop_heap(max.begin(),max.end(),less<int>());//删除最大堆的最大值
max.pop_back(); //在容器中删除
}
min.push_back(num);//压入最小堆
push_heap(min.begin(),min.end(),greater<int>());//调整最小堆
}
else//奇数时候,放入最大堆
{
if(min.size()>0 && num>min[0])
{
// push_heap (_First, _Last),要先在容器中加入数据,再调用push_heap ()
min.push_back(num);//先压入最小堆
push_heap(min.begin(),min.end(),greater<int>());//调整最小堆
num=min[0];//得到最小堆的最小值(堆顶)
//pop_heap(_First, _Last),要先调用pop_heap()再在容器中删除数据
pop_heap(min.begin(),min.end(),greater<int>());//删除最小堆的最大值
min.pop_back(); //在容器中删除
}
max.push_back(num);//压入数字
push_heap(max.begin(),max.end(),less<int>());//调整最大堆
}
}
/*获取中位数*/
double GetMedian()
{
int size=min.size()+max.size();
if(size<=0) //没有元素,抛出异常
return 0;//throw exception("No numbers are available");
if((size&1)==0)//偶数时,去平均
return ((double)(max[0]+min[0])/2);
else//奇数,去最小堆,因为最小堆数据保持和最大堆一样多,或者比最大堆多1个
return min[0];
}
};
// class Solution {
// public:
// void Insert(int num)
// {
// a.push_back(num);
// }
// double GetMedian()
// {
// int n = a.size();
// sort(a.begin(), a.end());
// if(n % 2 == 1)
// return a[n / 2];
// if(n % 2 == 0)
// return (a[n / 2] + a[n / 2 - 1]) / 2.0;
// }
// private:
// vector<int> a;
// };
滑动窗口的最大值
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> res = new ArrayList<Integer>();
if(num == null || num.length == 0 || size == 0) return res;
int rk = 1;
int ans = num[0];
for(int i = 0 ; i < num.length - size +1; i++){
for(int j = i;j < i + size; j++){
ans = Math.max(ans,num[j]);
}
res.add(ans);
if(i + 1 < num.length){
ans = num[i+1];//还原
}
}
return res;
}
}
// import java.util.*;
// public class Solution {
// public ArrayList<Integer> maxInWindows(int [] num, int size)
// {
// //思路时=是,一个双向链表存储小标,当当前元素比下标小时,入队列,大时,遍历队列,比该元素小时就舍弃,然后入队列
// //begin记录滑动窗口左边
// ArrayList res= new ArrayList<>();
// if(num==null||size==0||num.length<size){
// return res;
// }
// int begin=0;
// ArrayDeque<Integer> queue = new ArrayDeque<>();
// for(int i=0;i<num.length;i++){
// begin=i-size+1;//代表滑动窗口的起点
// if(queue.isEmpty()){
// queue.add(i);
// }else if(begin>queue.peekFirst()){
// queue.pollFirst();
// }
// while(!queue.isEmpty()&&num[i]>= num[queue.peekLast()]){
// queue.pollLast();
// }
// queue.add(i);
// if(begin>=0){
// res.add(num[queue.peekFirst()]);
// }
// }
// return res;
// }
// }
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int>max;
if(num.empty()||size>num.size()||size<1)
return max;
int m;
for(int i=0;i<num.size()-size+1;i++)
{
m=num[i];
for(int j=i+1;j<i+size;j++)
{
if(num[j]>m)
{
m=num[j];
}
}
max.push_back(m);
}
return max;
}
};
// class Solution {
// public:
// vector<int> maxInWindows(const vector<int>& num, unsigned int size)
// {
// vector<int> ret;
// if (num.size() == 0 || size < 1 || num.size() < size) return ret;
// int n = num.size();
// deque<int> dq;
// for (int i = 0; i < n; ++i) {
// while (!dq.empty() && num[dq.back()] < num[i]) {
// dq.pop_back();
// }
// dq.push_back(i);
// // 判断队列的头部的下标是否过期
// if (dq.front() + size <= i) {
// dq.pop_front();
// }
// // 判断是否形成了窗口
// if (i + 1 >= size) {
// ret.push_back(num[dq.front()]);
// }
// }
// return ret;
// }
// };
矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如
矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
//标志位,初始化为false
boolean[] flag = new boolean[matrix.length];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
//循环遍历二维数组,找到起点等于str第一个元素的值,再递归判断四周是否有符合条件的----回溯法
if(judge(matrix,i,j,rows,cols,flag,str,0)){
return true;
}
}
}
return false;
}
//judge(初始矩阵,索引行坐标i,索引纵坐标j,矩阵行数,矩阵列数,待判断的字符串,字符串索引初始为0即先判断字符串的第一位)
private boolean judge(char[] matrix,int i,int j,int rows,int cols,boolean[] flag,char[] str,int k){
//先根据i和j计算匹配的第一个元素转为一维数组的位置
int index = i*cols+j;
//递归终止条件
if(i<0 || j<0 || i>=rows || j>=cols || matrix[index] != str[k] || flag[index] == true)
return false;
//若k已经到达str末尾了,说明之前的都已经匹配成功了,直接返回true即可
if(k == str.length-1)
return true;
//要走的第一个位置置为true,表示已经走过了
flag[index] = true;
//回溯,递归寻找,每次找到了就给k加一,找不到,还原
if(judge(matrix,i-1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i+1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i,j-1,rows,cols,flag,str,k+1) ||
judge(matrix,i,j+1,rows,cols,flag,str,k+1) )
{
return true;
}
//走到这,说明这一条路不通,还原,再试其他的路径
flag[index] = false;
return false;
}
}
// 分析:回溯算法
// 这是一个可以用回朔法解决的典型题。首先,在矩阵中任选一个格子作为路径的起点。如果路径上的第i个字符不是ch,那么这个格子不可能处在路径上的
// 第i个位置。如果路径上的第i个字符正好是ch,那么往相邻的格子寻找路径上的第i+1个字符。除在矩阵边界上的格子之外,其他格子都有4个相邻的格子。
// 重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。
// 由于回朔法的递归特性,路径可以被开成一个栈。当在矩阵中定位了路径中前n个字符的位置之后,在与第n个字符对应的格子的周围都没有找到第n+1个
// 字符,这个时候只要在路径上回到第n-1个字符,重新定位第n个字符。
// 由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。 当矩阵中坐标为(row,col)的
// 格子和路径字符串中相应的字符一样时,从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下一个字符
// 如果4个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字符在矩阵中的定位不正确,我们需要回到前一个,然后重新定位。
// 一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置
class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
if(str==NULL||rows<=0||cols<=0)
return false;
bool *isOk=new bool[rows*cols]();
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
if(isHsaPath(matrix,rows,cols,str,isOk,i,j))
return true;
}
return false;
}
bool isHsaPath(char *matrix,int rows,int cols,char *str,bool *isOk,int curx,int cury)
{
if(*str=='\0')
return true;
if(cury==cols)
{
curx++;
cury=0;
}
if(cury==-1)
{
curx--;
cury=cols-1;
}
if(curx<0||curx>=rows)
return false;
if(isOk[curx*cols+cury]||*str!=matrix[curx*cols+cury])
return false;
isOk[curx*cols+cury]=true;
bool sign=isHsaPath(matrix,rows,cols,str+1,isOk,curx-1,cury)
||isHsaPath(matrix,rows,cols,str+1,isOk,curx+1,cury)
||isHsaPath(matrix,rows,cols,str+1,isOk,curx,cury-1)
||isHsaPath(matrix,rows,cols,str+1,isOk,curx,cury+1);
isOk[curx*cols+cury]=false;
return sign;
}
};
机器人的运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
public class Solution {
public int movingCount(int threshold, int rows, int cols) {
if (rows <= 0 || cols <= 0 || threshold < 0)
return 0;
boolean[][] isVisited = new boolean[rows][cols];//标记
int count = movingCountCore(threshold, rows, cols, 0, 0, isVisited);
return count;
}
private int movingCountCore(int threshold,int rows,int cols,
int row,int col, boolean[][] isVisited) {
if (row < 0 || col < 0 || row >= rows || col >= cols || isVisited[row][col]
|| cal(row) + cal(col) > threshold)
return 0;
isVisited[row][col] = true;
return 1 + movingCountCore(threshold, rows, cols, row - 1, col, isVisited)
+ movingCountCore(threshold, rows, cols, row + 1, col, isVisited)
+ movingCountCore(threshold, rows, cols, row, col - 1, isVisited)
+ movingCountCore(threshold, rows, cols, row, col + 1, isVisited);
}
private int cal(int num) {
int sum = 0;
while (num > 0) {
sum += num % 10;
num /= 10;
}
return sum;
}
}
class Solution {
public:
int movingCount(int threshold, int rows, int cols)
{
int count = 0;
for(int i = 0 ; i < rows ; ++i)
{
for(int j = 0 ; j < cols ; ++j)
{
if(coon(i)+coon(j) <= threshold)
count++;
else if(rows==1||cols==1)
{
return count;
}
}
}
return count;
}
int coon(int x) {
int sum = 0;
while(x) {
sum += x%10;
x /= 10;
}
return sum;
}
};
剪绳子
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
public class Solution {
public int cutRope(int target) {
int max = 1;
if(target >0 && target < 3)
return target - 1;
while(target > 4){// > 4
target -= 3;
max *= 3;
}
return max * target;
}
}
/*
public static int cutRope(int n) {
if(n==2){
return 1;
}else if(n==3){
return 2;
}
if(n%3==0){
return (int)Math.pow(3,n/3);
}else if(n%3==1){
return 4*(int)Math.pow(3,n/3-1);
}else {
return 2*(int)Math.pow(3,n/3);
}
}
*/
class Solution {
public:
int cutRope(int target) {
int max=1;
if(target<=3 && target>0){
return target-1;
}
while(target>4){
target-=3;
max*=3;
}
return max*target;
}
};
//问题类似于定周长求最大面积的问题(例如给定四边形周长,求最大面积),当k[0]==k[1]==,==k[m]时乘积最大,设k[0]=x,那么n=x*m,乘积可以用下式表示
//f(x)=(x)^(n/x)
//求导令为0,得x=e约等于2.7,取整数位3