剑指offer(1/20)

二叉搜索树的第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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值