
剑指offer(牛客)
快乐的小J
基础不牢,地动山摇。
展开
-
机器人的运动范围
思路:使用递归,结合访问状态矩阵。 //判断row行,col列的格子是否可以进入 public static boolean checkPosition(int threshold, int row,int col){ int sum=0; int tmpRow=row,tmpCol=col; while(tmpRow!=0)...原创 2019-08-21 14:45:38 · 96 阅读 · 0 评论 -
把字符串转换成整数
思路:问题比较简单,主要是考察细节能力,在编写代码过程中或之后,应该尽量考虑到所有可能的输入,例如:(1)输入为空、长度为零的“”、空格“ ”。(2)输入为带有正负号的数字“+123456789”,如果带两个符号呢“++1”,应该判错。(3)输入数字太大 or 太小,导致越界。这个问题在剑指offer的解决方法是使用long类型先保存结果,然后判断越界,但是如果输入的是一个超级无敌...原创 2019-07-19 13:41:01 · 134 阅读 · 0 评论 -
翻转单词顺序
思路:分别将每个单词翻转,然后拼接位一个句子,再将句子翻转。需要注意的点:单词是根据空格识别的,当一个句子没有单词只有空格,需要额外处理。 public String ReverseSentence(String str) { if(str==null||str.length()==0) return str; String answer=""; ...原创 2019-07-16 16:35:09 · 137 阅读 · 0 评论 -
左旋转字符串
剑指offer的思路:三次逆序构成左旋。使用java自带方法,比较简单,但是时间复杂度可能稍高。 public String LeftRotateString(String str,int n) { if(str==null||str.length()==0||n<=0||n>=str.length()) return str; retu...原创 2019-07-16 16:15:04 · 86 阅读 · 0 评论 -
和为S的两个数字
思路:维持两个指针left和right,分别从数组两端开始查找:(1)若array[left]+array[right]==sum,返回{array[left],array[right]};(2)若array[left]+array[right]<sum,左指针left移动,增大和值;(3)若array[left]+array[right]>sum,右指针right移动,减小和值...原创 2019-07-16 15:47:58 · 93 阅读 · 0 评论 -
和为sum的连续正数序列
1. 剑指offer的思路:维持left~right的连续整数区间,求和:(1)若该区间之和小于sum,right前移(right++);(2)若该区间之和等于sum,right前移,并且输出当前区间;(3)若该区间之和大于sum,left前移。循环结束条件是判断left是否超过了sum/2。public ArrayList<ArrayList<Integer...原创 2019-07-16 15:08:36 · 197 阅读 · 0 评论 -
不用加减乘除实现加法
思路:使用位运算,异或得到中间结果,与得到进位。 public int Add(int num1,int num2) { //变量定义 int num1Tmp=num1,num2Tmp=num2; //存放中间结果,若没有进位,中间结果就是最终结果 int valueAfterXOR=num1Tmp ^ num2Tmp;...原创 2019-07-18 14:30:08 · 97 阅读 · 0 评论 -
求1+2+3+...+n
要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。1. 用幂函数和移位 public int Sum_Solution(int n) { if(n<1) return -1; return ((int)Math.pow(n,2)+n)>>1; }2. 剑指...原创 2019-07-18 12:32:04 · 121 阅读 · 0 评论 -
圆圈中最后剩下的数字
1. 经典解法:用链表或数组模拟环,执行n-1次,输出最后剩下的数字。2. 剑指offer思路:通过推导,找到递推关系式,使用递归或循环解决。 public int LastRemaining_Solution(int n, int m) { if(n<1||m<1) return 0; int answer=0; for...原创 2019-07-18 12:09:55 · 93 阅读 · 0 评论 -
扑克牌顺子
思路:(1)利用数组给牌排序,单独统计0的数量;(2)定位到扑克牌第一张牌,向后寻找空缺,用0牌填充;(3)若0牌还有剩余,从扑克牌的第一张牌向前填充;(4)0牌依然剩余,不存在顺子,此时牌数大于13;(5)从顺子向后检查,若存在间断的牌,不存在顺子,否则这副牌符合顺子要求。 public static boolean isContinuous(int [] num...原创 2019-07-18 10:31:07 · 183 阅读 · 0 评论 -
数组中出现一次的数字
思路来自剑指offer,采用异或的思路:(1)将全部元素异或得到关键元素key;(2)根据key的某一非零位将数组划分为两个子数组,此时两个单独出现的数字分别在两个子数组中;(3)两个子数组的全部元素分别异或,获得两个单独出现的数字。 /** * 关键变量命名为key,通过key将array分为两个数组 * flag记录key中某一个不为零的位置 ...原创 2019-07-05 17:11:39 · 89 阅读 · 0 评论 -
判断是否为平衡二叉树
一般思路:采用递归,从根节点出发,判断左边平衡、右边平衡;获得左侧树高、右侧树高;判断当前是否平衡。剑指offer的优化思路:由于上述自顶向下需要重复遍历结点效率降低,因此采用自底向上,每一层返回是否平衡以及当前树高,供给上一层使用,提高效率。算法的点:每一层使用Answer数组返回平衡与否的信息以及当前树高,只要发现不平衡,可以提前终止。import java.lang.Math;...原创 2019-07-05 16:32:49 · 161 阅读 · 0 评论 -
二叉树的深度
没什么写的。 public int max(int a,int b){ return a>b?a:b; } public int TreeDepth(TreeNode root) { if(root==null) return 0; return max(TreeDepth(root.left),TreeDepth(...原创 2019-07-05 15:53:49 · 95 阅读 · 0 评论 -
数字在排序数组中出现的次数(二分法求取大于K的最小值、小于K的最大值的下标)
思路:假如给定数组{1,2,2,2,3,3,5,6},求解2出现的次数,步骤如下:(1)求解小于2的最大值下标leftBound,若不存在(即2是左边界元素或小于所有元素),返回-1;(2)求解大于2的最小值下标rightBound,若不存在(即2是右边界元素或大于所有元素),返回length+1;(3)判断leftBound与rightBound之间的元素个数,若rightBound...原创 2019-07-05 15:45:07 · 792 阅读 · 0 评论 -
数组中重复的数字
思路1:时间复杂度O(n),空间复杂度O(n),不修改原数组。建立哈希表,将n个数字依次存储到哈希表中,出现重复即返回结果。思路2:时间复杂度O(n),空间复杂度O(1),修改原数组。长度为n的数组,若没有重复,那么numbers[i]应该在第numbers[i]位置上,但是由于某些数字重复,导致这些数字的位置放不下多余的数字,并且部分数字缺失。将numbers[i]与其下标i比较:...原创 2019-07-19 14:30:30 · 104 阅读 · 0 评论 -
构建乘积数组
思路:分为两个大三角计算,构建两个子数组,起始值为1,迭乘A[i++];B中每一个元素由两个子数组的对应项相乘得到。 public int[] multiply(int[] A) { if(A==null||A.length==0) return A; //变量定义 int length=A.length; ...原创 2019-07-19 15:30:41 · 92 阅读 · 0 评论 -
正则表达式匹配
思路:从前向后匹配,匹配成功的条件是字符串与模式的两个指针都移动到末尾:(1)若当前字符与模式当前字符匹配: a. 若模式当前字符之后跟的不是'*',那么字符串与模式同时移动一位指针; b. 若模式当前字符之后跟的是'*',需要分为三种情况,只要有一种匹配成功即可:字符串指针不移动&模式指针移动两位;字符串指针移动一位&模式指针不移动;字符串指针移动...原创 2019-07-22 11:27:25 · 176 阅读 · 0 评论 -
矩阵中的路径
思路:扫描矩阵中所有字符,以该字符为起点,检测是否存在路径;需要注意的点:回溯过程需要“恢复现场”。为了确保检测过程中不会重复进入同一个格子,需要设置visited数组,向下递归检索时,需要设置当前位置状态为“已搜索”,向下递归结束之后,返回上一层需要恢复当前位置状态为“未搜索”。 public boolean hasPathCore(char[] matrix, int ro...原创 2019-08-21 11:23:50 · 86 阅读 · 0 评论 -
滑动窗口的最大值
思路(来自剑指offer):扫描一遍数组,使用双向队列,队列中存储元素下标。(1)从队头开始检测,移除队列中所有符合以下条件的下标:队头下标与当前元素下标之差大于等于窗口大小;(2)从队尾开始检测,移除队列中所有符合以下条件的下标:队尾下标对应元素小于当前元素;(3)将当前元素队尾入队;(4)当前窗口对应的最大值为队头下标对应的元素。 public static A...原创 2019-08-21 10:25:57 · 146 阅读 · 0 评论 -
数据流中的中位数
剑指offer提供了许多思路:(1)直接插入&快排partition()方法寻找第k个数字;(2)插入排序或链表&直接获取中位数;(3)二叉搜索树(结点添加子树结点数量的字段);(4)平衡二叉搜索树;(5)利用最大堆与最小堆,分别储存数据流中较大的一半数字和较小的一半数字。采用思路:最大堆与最小堆,使用java中的PriorityQueue实现两个堆,在...原创 2019-08-20 22:34:34 · 98 阅读 · 0 评论 -
二叉搜索树的第k个结点
思路:二叉搜索树的中序遍历是有序的。 ArrayList<TreeNode> midTraceForKthNode(TreeNode pRoot,int k){ ArrayList<TreeNode> sortedList=new ArrayList<>(); if(pRoot==null||sortedList....原创 2019-08-20 20:57:51 · 104 阅读 · 0 评论 -
序列化二叉树
思路:因为可以使用'#'表示空结点,先序遍历就足够了;如果不能使用空结点符号,需要同时使用先序遍历和中序遍历;序列化思路:直接递归即可,要注意'!'分隔符的添加,不要重复;反序列化思路:字符串的第一个结点是根结点,第二个结点是左子树根结点,必须将左子树全部构建完成才可以构建右子树,因此每构建一个结点连接到树上,需要将该结点的字符从字符串前段删除,该过程使用递归解决;当左子树构建...原创 2019-08-20 20:30:58 · 87 阅读 · 0 评论 -
把二叉树打印成多行
思路:使用队列,通过宽度优先遍历,每完整添加一层结点,就在最后入队null分隔符。具体做法:入队null和pRoot,扫描到null分隔符,输出该层到answer并在当前队尾添加分隔符,否则将结点的孩子结点入队。 public static ArrayList<ArrayList<Integer> > queuePrint(TreeNode pRoot)...原创 2019-08-20 19:03:09 · 91 阅读 · 0 评论 -
按之字形顺序打印二叉树
思路:使用两个栈,从stackOut弹出结点并添加到当前层,将该结点的孩子结点按照下一轮打印顺序压入stackIn。 public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { if(pRoot==null) return new ArrayList<>(); ...原创 2019-08-19 17:11:21 · 82 阅读 · 0 评论 -
对称的二叉树
思路:使用递归,判断左孩子与右孩子是否相等;如果相等,进而判断:左孩子左子树与右孩子右子树,以及左孩子右子树与右孩子左子树。 public static boolean treeEqual(TreeNode left,TreeNode right){ if(left==null&&right==null) return true; ...原创 2019-08-19 16:20:52 · 100 阅读 · 0 评论 -
二叉树的下一个结点
思路:根据当前结点pNode的位置,分为以下几种情况:(1)pNode有右子树:以pNode的右孩子为起点,寻找最左端的结点,返回。(2)pNode没有右子树: 1)pNode没有父节点,返回空; 2)pNode有父节点,并且pNode是父节点的左孩子,返回父节点; 3)pNode有父节点,并且pNode是父节点的右孩子,此时...原创 2019-08-19 15:28:36 · 106 阅读 · 0 评论 -
删除链表中重复的结点
思路:利用两个指针(p2,p3)可以检查重复结点,为了保留父结点的信息,需要引入另一个指针(p1),用于删除重复结点之后的连接工作。public ListNode deleteDuplication(ListNode pHead) { if(pHead==null) return pHead; ListNode pNewHead=new List...原创 2019-07-22 21:02:53 · 109 阅读 · 0 评论 -
链表中环的入口结点
思路:分为三个步骤:(1)利用快慢指针判断有环;(2)利用双指针获取环的长度;(3)一号指针先前进环长度的步数,然后二号指针与一号指针同时同速度前进,直到相遇。public static ListNode EntryNodeOfLoop(ListNode pHead) { if(pHead==null) return pHead; ...原创 2019-07-22 20:10:43 · 83 阅读 · 0 评论 -
字符流中的第一个字符
思路:借助Hashmap,key保存字符,value保存位置,若重复出现,位置设置为-1。 //变量定义 public HashMap<Character,Integer> mapForUnrepeatableChar=new HashMap<>(); public int charCounter=0; //方法定义 /...原创 2019-07-22 16:27:20 · 151 阅读 · 0 评论 -
表示数值的字符串
思路:这是一道观察题目,找到数值字符串的模式,然后将模式描述为代码语言。一个完整的例子类似于:+12.34e-56;可以发现以下几点:(1)最多包含四个非数字符号:基数符号,基数小数点,e或E,指数符号位;(2)如果四个符号位都存在,那么有以下规则: a. 基数的符号位在0的位置; b. 任何一个符号都不会出现在字符串末尾,并且不会出现两次(这里将基数符...原创 2019-07-22 15:35:47 · 111 阅读 · 0 评论 -
第一个只出现一次的字母
题目中有指明“全部是字母,区分大小写”。构建映射表,一次遍历并记录。 public static int FirstNotRepeatingChar(String str) { if(str==null) return -1; boolean[] count=new boolean[58];//记录是否第一次出现 int[] pos...原创 2019-06-30 16:38:13 · 305 阅读 · 0 评论 -
丑数
思路:设定初始丑数列表,每次寻找最近的一个丑数。由于丑数的因子只能是2,3,5,所以需要将list中所有已知丑数乘以2,3,5,然后所有候选中大于当前最大丑数的最小丑数就是下一个丑数。为了提高效率,被判断出已经在当前列表的元素,不需要重复计算。import java.util.*;public class Solution { public int minNumber(i...原创 2019-06-30 15:41:33 · 163 阅读 · 0 评论 -
两个链表的第一个公共结点
思路:(1)分别扫描两个链表,获取二者的长度;(2)设定两个指针分别指向两个链表;(3)获得长度差值delta,让较长的链表对应的遍历指针先走delta步,此时两个指针位于同步;(4)两个指针同步前进,判断相等,即为answer。public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { ...原创 2019-07-05 14:30:18 · 84 阅读 · 0 评论 -
树的子结构(树A是否包含树B)
1. 分解为三个子问题,A包含B;A.left包含B;A.right包含B。 public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root1==null||root2==null) return false; else{ boolean flag=false;...原创 2019-04-16 10:29:49 · 415 阅读 · 0 评论 -
有序链表归并
常规题目。需要注意的点:判空。 public ListNode Merge(ListNode list1,ListNode list2) { if(list1==null&&list2==null) return null; else if(list1==null&&list2!=null) return list2;...原创 2019-04-16 09:50:04 · 312 阅读 · 0 评论 -
返回链表倒数第k个结点
常规题目。需要注意的点有:1. 链表为空;2. k<=0; 3.链表长度不足k。 public ListNode FindKthToTail(ListNode head,int k) { if(head==null || k<=0) return null; int count=0; ListNode firster,se...原创 2019-04-15 20:36:08 · 110 阅读 · 1 评论 -
调整数组顺序使奇数在偶数前面
1. 牛客网上那道还有附加条件“奇数与奇数的先后次序不变,偶数与偶数的先后次序保持不变”。这里我只想到一种很low的暴力方法,就是遍历,空间复杂度为O(N),时间复杂度为O(2N)。 int pointer=0; int[] arr_answer=array.clone(); for(int elem : arr_answer){ ...原创 2019-04-15 20:11:56 · 126 阅读 · 0 评论 -
浮点数的整数次方
需要考虑底数与指数分别为正零负九种情况。容易忽略的点:1.整数次幂,不是正数次幂;2.底数为零,指数为负;底数为零,指数为零;3.比较base与零相等,要注意double类型的特殊性;4.可以通过递归降低时间复杂度;5.除2操作可以通过移位提高效率。public static double Power(double base, int exponent) { b...原创 2019-04-15 17:21:56 · 556 阅读 · 0 评论 -
二进制中1的个数
1. 常规方法:flag左移,统计target&(flag)!=0的次数public int NumberOf1(int n) { int flag=1,count=0,target=n; while(flag!=0){ if((target&flag)!=0){ count++; ...原创 2019-02-27 11:23:19 · 129 阅读 · 0 评论 -
费波纳茨数列、跳台阶、矩形覆盖,另变态跳台阶
1. 用循环,不用递归;public int Fibonacci(int n) { int fib0=0,fib1=1,fib2=1; if(n==0) return fib0; if(n==1) return fib1; for(int i=2;i<=n;i++){ fib2=fib0+fib1;...原创 2019-02-27 11:18:15 · 215 阅读 · 0 评论