1.
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 问题:
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
来源:力扣(LeetCode)
总结:数组为空和长度为0是两个事情
重载T toArray(T a)这个一直报错
数组的创建,
一开始不给他分配多大可以吗?然后后面再循环一个一个给他加,试过了,我的报错,哭了
解析:通过Index 和 LastIndexOf()判断数组元素是否有相同
java,for循环,多个变量一起循环:for(a=1,b=2,c=3;a<b;a++,b--,c++){}逗号隔开就行。
面向对象的数组:
增删改查
查找算法:
线性查找: 拿着照片遍历查找(效率低)
二分法:(数组是有序的)
栈:
有点像汉诺塔,还有像 弹夹的例子。
用数组实现:1.把栈顶看成数组末尾。
增加和删除都在数组末尾进行
队列:(银行排队原理,先来先到)
代码实现:
1. 从队头出(数组的第0个元素取出)
2.创建新的数组(长度原来-1)
进入:
1.从数组的末尾进入
单链表:
结构:数据+下一个节点的地址
自己写:
Node类。包含两个字段,Node类型的next, int 类型的data
功能:
1. 增加到末尾
- 在这个方法里面新建Node类型的 current类型
- while(死循环) 退出的因素,没有nextNode为空了/ 循环里面再新建nextNode字段=current.next
- 然后将current设置为 为null的空节点,之后,把这个需要新增的元素,放在currentNode的nextNode字段下面
2.找到下一个元素、、
String 題目類:
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路:
1.創建新的一個stringbuffer str
2.判斷,儅charAt(“”)成立的時候,添加%20
3.else ,就把str[i]複製給新的str2
總結:
1.Stringbuffer 内存效率高,對他修改不會想STring類那樣創建新的對象,因此内存效率高
2.String buffer 有 CHarAt(“”) ,根據值找索引。 Index of()返回子字符串的索引
3. STRingbuffer replace , 將 一段位置標注出來(start,end)。用Str去替代
链表总结:
Java有链表类 ListNode ,可以直接新建 ListNode ln=new ListNode(5)
class ListNode {
ListNode next;
int val;
ListNode(int x){
val = x;
next = null;
}
}方法有 add.next() isEmpty()
属性 int value
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路:
1. 迭代链表,将value装进stack
2. 将stack 迭代pop给ArrayList
总结:
Stack 可以和ListNode一样创建,带式构造方法不带参数,需要导入包
ArrayList没有addFirst()方法
思路总结:
概念引入:假如有环,两个指针,一个快的pFast一个慢的pSLow。快的速度是慢的两倍
当相遇在C点的时候,让快指针重新回到起点,并且速度和慢指针一样,记为慢指针2。重新走过第一次慢指针的路径长度时,慢指针2和慢指针1在相遇在C点。但是因为他们速度相同,所以他们肯定在环的起始就相遇了。所以循环推出的条件是
(pSlow2=pSLow),否则他们就一直循环,返回相等的那个点
//先说个定理:两个指针一个fast、一个slow同时从一个链表的头部出发//fast一次走2步,slow一次走一步,如果该链表有环,两个指针必然在环内相遇//此时只需要把其中的一个指针重新指向链表头部,另一个不变(还在环内),//这次两个指针一次走一步,相遇的地方就是入口节点。//这个定理可以自己去网上看看证明。public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead){ ListNode fast = pHead; ListNode slow = pHead; while(fast != null && fast.next !=null){ fast = fast.next.next; slow = slow.next; if(fast == slow) break; } if(fast == null || fast.next == null) return null; fast = pHead; while(fast != slow){ fast = fast.next; slow = slow.next; } return fast; }}题目三:
思路:为了便于开始处理第一个元素(1),从第二个元素开始判断。加入标志性的头节点。
设置两个指针,pre表示符合要求的,next用来表示 用来工作的指针
非递归的代码:
1. 首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况
2.设置 pre ,last 指针, pre指针指向当前确定不重复的那个节点,而last指针相当于工作指针,一直往后面搜索
if (pHead==null || pHead.next==null){return pHead;}ListNode Head = new ListNode(0);Head.next = pHead;ListNode pre = Head;ListNode last = Head.next;while (last!=null){ if(last.next!=null && last.val == last.next.val){ // 找到最后的一个相同节点 while (last.next!=null && last.val == last.next.val){ last = last.next; } pre.next = last.next; last = last.next; }else{ pre = pre.next; last = last.next; }}return Head.next;站和队列:
题目1:
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
//引用马客(Mark)的解题思路,马客没加注释,我用自己的理解加下注释,希望对你们有用,//如有错误,见谅,我会及时修改。//deque s中存储的是num的下标class Solution {public: vector<int> maxInWindows(const vector<int>& num, unsigned int size) { vector<int> res; deque<int> s; for(unsigned int i=0;i<num.size();++i){ while(s.size() && num[s.back()]<=num[i])//从后面依次弹出队列中比当前num值小的元素,同时也能保证队列首元素为当前窗口最大值下标 s.pop_back(); while(s.size() && i-s.front()+1>size)//当当前窗口移出队首元素所在的位置,即队首元素坐标对应的num不在窗口中,需要弹出 s.pop_front(); s.push_back(i);//把每次滑动的num下标加入队列 if(size&&i+1>=size)//当滑动窗口首地址i大于等于size时才开始写入窗口最大值 res.push_back(num[s.front()]); } return res; }};思路分析:
第一种解决方案
常规操作:
1.左指针右指针分别在数组上滑动
2.循环i在滑动过程中(终止条件,right指针超过数组的边界),调用查找最大值的函数,返回每次滑动过程的最大值。
第二种操作方案:
采用双队列(尾端(相当于左端)到初始端,排列顺序从小到大),循环队列里面的值与数组里的比较,数组的大的话,就相当于排序放在双头队列里面(删除比他小的)。保证开头一直是最大的。还需要考虑一个情况,双头队列中的值过期的情况,i-size<peakFirst()的值,就可以删掉这个过期的值了pollFirst()。
输出结果的条件:当i>size-1的时候,相当于宽度已经到达了3了,已经可以开始华东取最大值了
总结:
1.LinkedList 是双头队列,具有安全的查询(peek(peekFirst,last方法))和增加(addLast,addFirst)安全的删除(poolFirst,poolLast方法)
树:
题目一:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
通过左子树和右子树递归找到每个节点。
总结前序遍历是 根节点,左节点,右节点这样的顺序。中序遍历是左节点,根节点,右节点这样的顺序。front节点表示前序遍历的列表。mid节点表示中序遍历的列表。
分析:
1根节点每次都是等于前序节点的第一个节点
2.根据找到的根节点(得到一个count指针),在中序遍历里面能够找到左子树的范围(根节点前面所有的值)left2 到left2+count
3.根据根节点可以在找到右子树的范围(left2+count+1 到 right2的范围)
遍历条件:
1.node.left(pre,in,left1+1,left1+count,left2,left2+count-1)
2.node.right(pre,in,left1+count+1,right1,left2+count+1,right2)
边界条件:1.front 和 mid 不为空
2.两个列表左节点的需要小于长度
3.左节点的长度也要小于右节点的长度。
题目二:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:反正返回的是这个点的中序遍历的下一个节点。所以分为几种情况
1.该节点有右节点
2.该节点无右节点
- 属于父节点的左节点,直接返回父节点
- 属于右节点,返回该节点的父节点的父节点(中序排序造成)
边界条件:
1. pNode该节点是初始根节点,直接返回null
2.PNode无右子树的情况下,没有left及right 元素,为空,会报空指针异常(判断方式,如果他父节点的父节点的左节点和Pnode的父节点不是同一个值就说明是这种异常情况,因此返回Null)
题目三
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
思路:
1.创建变量 num记录奇数层还是偶数层 创建队列,用来存储待处理的种子节点。在每次处理每层的过程中创建零食List装从队列里面取出的值。创建Sum值,初始化为root的个数也就是一。当在处理每层的过程中,创建temp变量,记录下一层的处理的个数。这一层循环处理结束后,将sum的值变为Temp的值。
2.两层循环,第一层循环判断队列是否为空,第二层处理每一层的取到元素加入零时List里面
3.将零时的List(当num为偶数的时候,处理一下倒序,技术的时候不用管)加入最终结果的LIst
临界条件:
1.判断队列是否为空,
2.判断左右节点是否有
3.判断根节点是否为空
题目四:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。例如,传入的数据为:[5,2,3,4,1,6,7,0,8],那么按照要求,输出是"5.00 3.50 3.00 3.50 3.00 3.50 4.00 3.50 4.00 "
思路:
1.用两个堆排序(这里用java的封装对象 小顶堆,排序方式是从小到大PriorityQueue,poll的方式是弹出队首元素,因此小顶堆弹的是最大值,大顶堆弹得是最小元素)
2.定义当目前的元素个数为奇数的时候,增加到小顶堆里面;反之增加到大顶堆里面。增加完之后。奇偶性发生改变,用参数sum记录奇偶性
3.判断大顶堆的最小值和小顶堆的最小值比较,如果最大值大于最小值则交换。
3.根据sum奇偶性判断中位数 。
总结:
1.Priority队列,自动默认从大到小排序。该队列因为是队列,所以先进先出,出的时候只能考虑poll()取得队首元素(默认表示最小值)
排序:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路总结:
迭代:
1.跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
遞歸:很簡單
動態規劃。就是把那個關係式對應的子問題的結果用數組存儲,遍歷(循環)然後返回arr[target]的值
2一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路 和上題類似,增加一個sum變量,記錄前面每一步的結果,循環對arr[i]進行賦值,更新sum的值
arr[i]=sum+1
sum=sum+arr[i]的值