数字与矩阵
//时间复杂度 O(n) 空间复杂度O(1)
import java.util.*;
public class Solution {
public int duplicate (int[] numbers) {
/*
不合法
(1)长度为0
(2)内容不再0到n-1之间
*/
if(numbers.length == 0)
return -1;
for(int i = 0;i < numbers.length;i++)
if(numbers[i] >= numbers.length || numbers[i] < 0)
return -1;
/*
合法输入
1、其中有重复元素
对每一个位置上的值进行核验,直到其中的值与下标值相等则检查下一位置
核验过程中将当下位置上的值交换给与该值一致的下标对应位置
(1)若要交换的目标位置其中值已于下标一致说明重复,返回该值
(2)若不一致,则进行交换
2、其中没有重复元素
*/
for(int i = 0 ; i < numbers.length ; i++){
while(numbers[i] != i){
if(numbers[numbers[i]] == numbers[i])
return numbers[i];
int temp = numbers[numbers[i]];
numbers[numbers[i]] = numbers[i];
numbers[i] = temp;
}
}
return -1;
}
}
public class Solution {
public boolean Find(int target, int [][] array) {
//不合法
if(array == null)
return false;
/*
合法
(1)存在
从右上角开始搜查
target比当前大向下搜查
target比当前小向左搜查
(2)不存在
*/
int row = 0, column = array[0].length-1;
while(row < array.length && column >= 0){
if(array[row][column] > target)
column--;
else if(array[row][column] < target)
row++;
else
return true;
}
return false;
}
}
//时间复杂度O(n)
import java.util.*;
public class Solution {
public String replaceSpace (String s) {
//不合法
if(s.isEmpty())
return s;
/*
合法
p1记下原字符串末尾位置
对原字符串进行搜查,遇到一个空格则在之后追加两个空格(空格位置改为%20,相较之前多了两个字符,故遇到一个空格要追加两个)
当p1指向为空格时,p2依次向前填充上0 2 %
当p1指向不为空格时,p2赋值为p1指向字符
*/
int p1 = s.length() - 1;
StringBuffer str = new StringBuffer(s);
for(int i = 0 ;i < s.length() ; i++)
if(s.charAt(i) == ' ')
str.append(" ");
int p2 = str.length() - 1;
while(p1>=0){
if(str.charAt(p1) == ' '){
str.setCharAt(p2--,'0');
str.setCharAt(p2--,'2');
str.setCharAt(p2--,'%');
}
else{
str.setCharAt(p2--,str.charAt(p1));
}
p1--;
}
return str.toString();
}
}
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> array = new ArrayList<>();
//不合法
if(matrix == null)
return array;
int row = matrix.length;
int column = matrix[0].length;
/*
圈数取决于行和列中比较小的值
若为奇数则减1除2再加一为总圈数
若为偶数先减1导致除2后结果少了1,再加上即为所求
*/
int circle = ((row < column?row:column)-1)/2+1;
for(int i = 0;i < circle; i++){
//上
for(int j = i; j < column - i;j++)
array.add(matrix[i][j]);
//右
for(int j = i+1; j < row - i; j++)
array.add(matrix[j][column-i-1]);
//下,在进行是要看上和下是否重合重合则不必输出
for(int j = column - i-2; (j >= i)&&(i!=row-i-1); j--)
array.add(matrix[row-i-1][j]);
//左,在进行是要看左和右是否重合重合则不必输出
for(int j = row - i - 2; (j > i)&&(i!=column-i-1); j--)
array.add(matrix[j][i]);
}
return array;
}
}
import java.util.HashMap;
public class Solution {
public int FirstNotRepeatingChar(String str) {
if(str.isEmpty())
return -1;
//因为map是无序的故要按照str中元素的顺序在遍历一遍才能找到最先出现的
HashMap<Character,Integer> map = new HashMap<Character,Integer>();
for(int i = 0; i < str.length(); i++){
/*
查看map是否包含该key,若包含则新得value会替换旧的
*/
if(map.containsKey(str.charAt(i))){
map.put(str.charAt(i),1);
}else{
map.put(str.charAt(i),0);
}
}
for(int i = 0; i < str.length(); i++){
if(map.get(str.charAt(i))==0)
return i;
}
return -1;
}
}
栈队列堆
import java.util.Stack;
public class Solution {
/*
入队:直接入stack1
出队:若stack2为空则stack1依次弹栈入stack2
然后将stack2栈顶弹出
*/
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.empty()){
while(!stack1.empty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
两个队列模拟一个栈
入栈:直接入队列1
出栈:将队列1中元素依次出队入队列2,最后一个元素作为出栈元素
public class Solution {
/*
从pushA的第一个元素开始,在分别指向pushA和popA的下标不超过长度的情况下
每次从pushA压一个元素入栈
如果当前栈顶元素与popindex指向元素一致则弹栈popindex++,直到栈顶与popA指向元素不同
(这里注意比较栈顶与popindex指向元素时,要保证栈不为空)
全部进行完后,若栈内为空说明popA与pushA匹配
否则不匹配
*/
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA == null || popA == null)
return false;
if(pushA.length != popA.length)
return false;
Stack<Integer> stack = new Stack<Integer>();
int pushindex = 0, popindex = 0;
while(pushindex < pushA.length && popindex < popA.length){
stack.push(pushA[pushindex++]);
while(!stack.empty()&&stack.peek()==popA[popindex]){
stack.pop();
popindex ++;
}
}
if(stack.empty())
return true;
return false;
}
}
(1)利用Java中的优先队列,堆排序思想
/*
这里采用优先队列的思想(大顶堆)
维护一个大顶堆,每次加入元素后如果多余k个就删除最大的
所有加入一遍后就剩下了k个最小的。
PriorityQueue的用法
大顶堆 new PriorityQueue<Integer>((o1,o2)->(o2-o1));
小顶堆 new PriorityQueue< >();
自定义 Queue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
*/
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> ret = new ArrayList<>();
if(input == null || input.length == 0|| k > input.length)
return ret;
Queue<Integer> priorityQueue = new PriorityQueue<Integer>((o1,o2)->(o2-o1));
for(int i=0;i<input.length;i++){
/*
(一个重要的细节)
每次都要先将当前元素加入队列,再判断是否大于k个,删除最大的
(如果先删再加,就不能保证删除的这个元素是大于新加入的元素)
*/
priorityQueue.add(input[i]);
if(priorityQueue.size()>k)
priorityQueue.poll();
}
while(priorityQueue.size()>0){
Integer number = priorityQueue.poll();
ret.add(number);
}
return ret;
}
}
(2)利用快速选择
/*
利用快速排序的思想
找到第k个位置,这个位置之前的所有元素小于他,之后的所有元素大于他
(因为本题给出的要求的是输出的这个k个最小的数顺序可以是任意的所以可用该方法)
*/
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> ret = new ArrayList<>();
if(input == null||input.length<k||k<=0)
return ret;
int start = 0, end = input.length-1;
int index = partition(input,start,end);
//比较是一定要用k-1比较,用k比较虽然可以找到前k个最小,但会出现数组越界访问
while(index!=k-1){
if(index<k-1)
start = index+1;
if(index>k-1)
end = index -1;
index = partition(input,start,end);
}
for(int i = 0;i<k;i++){
ret.add(input[i]);
}
return ret;
}
private int partition(int[] input, int start, int end){
int number = input[end];
while(start<end){
while(start<end&&input[start]<=number)start++;
if(start<end)
input[end--] = input[start];
while(start<end&&input[end]>number)end--;
if(start<end)
input[start++] = input[end];
}
//不要忘记最后要把number放回他应该的位置
input[start] = number;
return start;
}
}
以上两个方法各有优劣
快排思想需要修改数组元素。
大顶堆思想不需要修改数组元素 ,但需要维护一个优先队列,适合海量数据(即n比较大,k比较小,不能够一次性将数据载入内存的)
import java.util.*;
/*
从第0个元素开始
第偶数个放左边,第奇数个放右边
为了保证左边永远小于右边所有元素,右边永远大于左边所有元素
则当一个元素要加入左边时,其可能并不小于右边,故先加入右,再弹出右边最小加入左边
反之依然
*/
public class Solution {
private Queue<Integer> left = new PriorityQueue<Integer>((o1,o2)->(o2-o1));
private Queue<Integer> right = new PriorityQueue<Integer>();
private int N = 0;
public void Insert(Integer num) {
if((N&1)==0){
right.add(num);
left.add(right.poll());
}
else{
left.add(num);
right.add(left.poll());
}
N++;
}
public Double GetMedian() {
if(N == 0)
return -1.0;
//因为是实时的插入获取,故这里计算中位数时只能获取不能弹出
//注意要求的返回值类型
if((N&1) == 0)
return Double.valueOf(left.peek()+right.peek())/2;
else
return Double.valueOf(left.peek());
}
}
import java.util.*;
public class Solution {
//Insert one char from stringstream
/*
不同字符对应不同的ASCII码共有128种
用一个长为128的数组记录每个字符出现的次数
用队列存储字符读取顺序
*/
private int[] num = new int[128];
private Queue<Character> queue= new LinkedList<>();
public void Insert(char ch)
{
num[ch]++;
queue.add(ch);
//保证每次读入操作后,队列的头元素都是目前为止首个为重复元素
while(!queue.isEmpty()&&num[queue.peek()]>1)
queue.poll();
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
return (queue.isEmpty())?'#':queue.peek();
}
}
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size) {
//存储滑动窗口最大值
ArrayList<Integer> arrayWindow = new ArrayList<>();
//对当前滑动窗口内的元素进行堆排序
PriorityQueue<Integer> max = new PriorityQueue<>((o1,o2)->o2-o1);
if( size <= 0 || size > num.length )
return arrayWindow;
/*
初始化arrayWindow和max堆
*/
for(int i = 0; i < size; i++){
max.add(num[i]);
}
arrayWindow.add(max.peek());
/*
模拟窗口滑动
窗口每移动一次,先从堆中删除从窗口中滑出的元素,再将新滑入的元素加入max堆中;
取max的peek获取最大值存入arraywindo
*/
for(int i = size; i < num.length; i++){
max.remove(num[i-size]);
max.add(num[i]);
arrayWindow.add(max.peek());
}
return arrayWindow;
}
}
双指针
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> list = new ArrayList<>();
/*
分别用两个值指向数组的头和尾
每次将头尾元素相加查看结果是否为sum
若<sum 头指针向后移动
若>sum 尾指针像前移动
*/
int head = 0 , tail = array.length-1;
while(head < tail){
if(array[head]+array[tail] == sum){
list.add(array[head]);
list.add(array[tail]);
return list;
}
else if(array[head]+array[tail]