(1)NC78反转链表
(2)NC140 排序
两种常用排序
用快排实现
public int[] MySort (int[] arr) {
fastSort(arr,0,arr.length-1);
return arr;
}
private void fastSort(int[] arr,int l,int r){
if(l>=r)
return;
int num = arr[r];
int sl = l,sr=r;
while(l<r){
while(l<r&&arr[l]<num) l++;
//在填入前一定要进行判断
if(l<r)
arr[r--] = arr[l];
while(l<r&&arr[r]>num)r--;
//在填入前一定要进行判断
if(l<r)
arr[l++] = arr[r];
}
arr[r] = num;
fastSort(arr,sl,l-1);
fastSort(arr,l+1,sr);
}
用归并法实现
public class Solution {
public int[] MySort (int[] arr) {
// write code here
mergeSort(arr,0,arr.length-1);
return arr;
}
private void mergeSort(int[] arr , int l , int r){
if(l>=r)
return;
int mid = (l+r)>>1;
//分两边继续递归
mergeSort(arr,l,mid);
mergeSort(arr,mid+1,r);
//两边都递归结束,才合并此层
merge(arr,l,mid,r);
}
private void merge(int[] arr,int l,int mid,int r){
int[] t = new int[r-l+1];
int index = 0;
int h1 = l, h2 = mid+1;
while(h1<=mid&&h2<=r){
if(arr[h1]<arr[h2])
t[index++] = arr[h1++];
else
t[index++] = arr[h2++];
}
while(h1<=mid)
t[index++]=arr[h1++];
while(h2<=r)
t[index++]=arr[h2++];
//注意记得将临时数组中的值转移到原数组中
for(int i = 0;i<t.length;i++)
arr[l++]=t[i];
}
}
堆排序
优先队列
返回形式
public int[][] threeOrders (TreeNode root) {
// 分辨用链表先存储
ArrayList<Integer> prelist = new ArrayList<Integer>();
ArrayList<Integer> inlist = new ArrayList<Integer>();
ArrayList<Integer> postlist = new ArrayList<Integer>();
preOrder(root,prelist);
inOrder(root,inlist);
postOrder(root,postlist);
//再根据链表长创建二维数组
int[][] res = new int[3][prelist.size()];
for(int i=0;i<prelist.size();i++){
res[0][i] = prelist.get(i);
}
for(int i=0;i<inlist.size();i++){
res[1][i] = inlist.get(i);
}
for(int i=0;i<postlist.size();i++){
res[2][i] = postlist.get(i);
}
return res;
}
本题可采用分会分治,可大顶堆。大顶堆实现起来更容易。或使用Array自带sort排序
import java.util.*;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(k<=0||input.length==0)
return res;
if(input.length<=k){
for(int i =0;i<input.length;i++)
res.add(input[i]);
return res;
}
PriorityQueue<Integer> queue = new PriorityQueue<Integer>((o1,o2)->(o2-o1));
for(int i = 0;i<input.length;i++){
if(queue.size()>=k){
if(queue.peek()>input[i]){
queue.poll();
queue.offer(input[i]);
}
}
else{
queue.offer(input[i]);
}
}
while(!queue.isEmpty()){
res.add(queue.poll());
}
return res;
}
}
(6)NC88 寻找第K大
使用快排,有两个注意的点
1、一定记住把,暂存的t放入
2、递归时,范围缩小的操作
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
if(n<=0||K>n)
return -1;
sortInt(a,0,n-1,K-1);
return a[K-1];
}
private void sortInt(int[] a, int l,int r,int k){
int t = a[r];
int nl = l,nr=r;
while(nl<nr){
while(nl<nr&&a[nl]>t)nl++;
if(nl<nr) a[nr--]=a[nl];
while(nl<nr&&a[nr]<=t)nr--;
if(nl<nr) a[nl++]=a[nr];
}
//记得把t返回去
a[nl]=t;
if(nl==k)
return;
//+1,-1范围缩小的操作,不然会引起死循环
if(nl<k)
sortInt(a,nl+1,r,k);
else
sortInt(a,l,nl-1,k);
}
}
没便利到一个数,target-当前 若在map中则将(当前值,下标)存入。若存在则找到了和为target的值。
public int[] twoSum (int[] numbers, int target) {
// write code here
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
int[] res = new int[2];
for(int i = 0;i<numbers.length;i++){
int last = target - numbers[i];
if(map.isEmpty()||!map.containsKey(last)){
map.put(numbers[i],i);
}
else{
res[0]=map.get(last)+1;
res[1]=i+1;
break;
}
}
return res;
}
public ListNode reverseKGroup (ListNode head, int k) {
// write code here
//寻找第k个结点。过程中出现null则不反转,直接但会当前链表
ListNode tail = head;
for(int i=0;i<k-1;i++){
if(tail==null)
return head;
tail = tail.next;
}
if(tail==null)
return head;
//记录下一次的起点
ListNode last = tail.next;
//将本次列表结尾置空,开始反转
tail.next = null;
ListNode h = new ListNode(0);
ListNode cur = head;
while(cur!=null){
ListNode p = cur.next;
cur.next = h.next;
h.next = cur;
cur = p;
}
//head指向的是第一个结点(也为反转后的最后一个结点),使器连接后面的反抓列
head.next = reverseKGroup(last,k);
//最终返回我们的而结果
return h.next;
}
sum记录当前和,sum+nextNumber大于nextNumber则将nextNumber加入总和,不然说明不能继续连续,以nextNumber为新起点。
每次计算后都比较更新max
1、l,r分别指向无重复数组头尾
2、新进加入数组的元素,若map中已存在,则需要重新更新起点。新起点为重复数字的下标的下一个。若此位置小于当先l,则说面重复数字不再当前范围内,故不更新
public int maxLength (int[] arr) {
// write code here
if(arr.length==0)
return 0;
int max = 1;
int l = 0, r=1;
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
map.put(arr[0],0);
while(r<arr.length){
//若重复位置的下一个下表小于当前l,则说明重复数字不再当前范围。
if(map.containsKey(arr[r])&&map.get(arr[r])+1>l){
l = map.get(arr[r])+1;
}
map.put(arr[r],r);
//每次更新完l,r重新判断是否活得最大长度
if(r-l+1>max){
max=r-l+1;
}
r++;
}
if(r-l>max){
max=r-l;
}
return max;
}
当由于后续为null,fast,slow不移动的情况。此时要将其直接置null。不然会世中卡在当前不能后移的结点位置
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
int index = 0;
while(index==0||slow!=fast){
if(slow!=null)
slow=slow.next;
else
slow =null;
if(fast!=null&&fast.next!=null){
fast = fast.next.next;
}
else
fast = null;
index = 1;
}
if(slow==null)
return false;
return true;
}
注意数据类型的选择,当需要一个可变长度的字符串时用StringBuffer
注意如何Collections.reverse用于list集合的反转。Collections.reverse(arr);
不需要通过改变左右孩子入队顺序去实现,只需将需从右到左遍历的行反转
dp[i][j]表示字符串str1中第i个字符和str2种第j个字符为最后一个元素所构成的最长公共子串。
-
如果不相等,那么他们就不能构成公共子串,也就是
dp[i][j]=0; -
如果相等,我们还需要计算前面相等字符的个数,其实就是dp[i-1][j-1],所以
dp[i][j]=dp[i-1][j-1]+1;(即其前一位为连续,则长度会增加1,前一位不为联系则此处为开始即0)
在实现是考虑到下表0减一为负。故二维数组i+1相当于i位置
public String LCS (String str1, String str2) {
// write code here
int[][] dp = new int[str1.length()+1][str2.length()+1];
int maxindex = 0;
int maxlength = 0;
//maxindex与maxlength在每次找到相等字符时进行递增。
for(int i = 0;i<str1.length();i++){
for(int j=0;j<str2.length();j++){
if(str1.charAt(i)==str2.charAt(j)){
dp[i+1][j+1]=dp[i][j]+1;
if(dp[i+1][j+1]>maxlength){
maxlength=dp[i+1][j+1];
maxindex = i;
}
}else{
dp[i+1][j+1]=0;
}
}
}
return str1.substring(maxindex-maxlength+1,maxindex+1);
}
递归方法:
注:若路径下无匹配则会遍历到叶子结点,一路向上返回null
1、当前结点为空,或与寻找值匹配。则返回当前结点。
对当前结点的左右进行递归,有以下几种情况
left=null right=null 返回null
left为空 返回right(若right不为null则说明其有匹配结点)
right为空 返回left(若left不为null则说明其有匹配结点)
若lef与right均不为空则,说明结果在两侧,则返回当前结点。
public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
// write code here
return dfs(root,o1,o2).val;
}
private TreeNode dfs(TreeNode root, int o1, int o2){
if(root==null||root.val==o1||root.val==o2){
return root;
}
TreeNode left = dfs(root.left,o1,o2);
TreeNode right = dfs(root.right,o1,o2);
if(left==null)
return right;
if(right==null)
return left;
return root;
}
非递归当打实现:
(1)map记录每个结点值对应的父节点值
如何对map进行初始化?采用层遍历,结束标志,map的key中包含o1和o2
(2)先将o1路径记录下来,用set记录,一路向上寻找父节点记录进set,直道不存在父节点(即map中无此key)
从o2向上依次遍历其父节点,若存在于set中则为最近公共结点
public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
// write code here
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
map.put(root.val,Integer.MAX_VALUE);
queue.add(root);
while(!map.containsKey(o1)||!map.containsKey(o2)){
TreeNode node = queue.poll();
if(node.left!=null){
queue.offer(node.left);
map.put(node.left.val,node.val);
}
if(node.right!=null){
queue.offer(node.right);
map.put(node.right.val,node.val);
}
}
Set<Integer> set = new HashSet<Integer>();
while(map.containsKey(o1)){
set.add(o1);
o1 = map.get(o1);
}
while(!set.contains(o2)){
o2 = map.get(o2);
}
return o2;
}
这里主要是String几个方法
预将String当成数组操作时 ch=str.toCharArray()
用char[] 生成String 时 new String(ch)
这里面有两个注意点
1、圈数:取row和col最小值计算圈
2、边界控制:输入下时判断此行,上是都已输入过
输入左时判断此列,右是否已输入过
public ArrayList<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> arr = new ArrayList<Integer>();
if(matrix.length==0)
return arr;
int row = matrix.length;
int col = matrix[0].length;
int cir = (row<col)?row:col;
cir = (cir%2==0)?cir/2:cir/2+1;
for(int c = 0;c<cir;c++){
for(int i = c;i<col-c;i++)
arr.add(matrix[c][i]);
for(int i = c+1;i<row-c-1;i++)
arr.add(matrix[i][col-c-1]);
//是否输出下行判断
if(c<row-c-1)
for(int i = col-c-1;i>=c;i--)
arr.add(matrix[row-c-1][i]);
//是否输出左行判断
if(c<col-c-1)
for(int i = row-c-2;i>=c+1;i--)
arr.add(matrix[i][c]);
}
return arr;
}
方法一:两种情况
偶数以当前位置i,i+1发散寻找
奇数当前位置为中心,i,i发散寻找
public int getLongestPalindrome (String A) {
// write code here
if(A==null||A.length()==0){
return 0;
}
int maxl = Integer.MIN_VALUE;
for(int i = 0;i<A.length();i++){
maxl = Math.max(maxl,Math.max(getl(A,i,i),getl(A,i,i+1)));
}
return maxl;
}
public int getl(String str,int l,int r){
while(l>=0&&r<str.length()&&str.charAt(l)==str.charAt(r)){
l--;
r++;
}
return r-l-1;
}
1、将数组排序
2、i指向元组第一个位置元素,
当i对应值大于0时则说明后面均大于零。可以停止寻找
当i对应值小于0,可转化为将后面的有序数组中两个值的和等于固定值0-num[i]
和大于0-num[i],r减小即指向更小一点儿的数
和小于0-num[i],l增大即指向更大一点儿的数
和与0-num[i]相等,则加入集合
3、可以加入集合,并不能停止寻找合等于0-num[i]的对
但需先去除重复元素,l,r从新的位置开始继续寻找
public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
if(num.length<3)
return res;
Arrays.sort(num);
for(int i = 0;i < num.length-2;i++){
if(num[i]>0)
break;
if(i>0&&num[i-1]==num[i])
continue;
int l = i+1;
int r = num.length-1;
while(l<r){
if(num[l]+num[r]==0-num[i]){
ArrayList<Integer> arr = new ArrayList<Integer>();
arr.add(num[i]);
arr.add(num[l]);
arr.add(num[r]);
res.add(arr);
//去除重复
while(l<r&&num[l+1]==num[l])
l++;
//去除重复
while(l<r&&num[r-1]==num[r])
r--;
//指向新的位置
l++;
r--;
}
else if(num[l]+num[r]>0-num[i])
r--;
else
l++;
}
}
return res;
}
import java.util.*;
public class Solution {
/**
* retrun the longest increasing subsequence
* @param arr int整型一维数组 the array
* @return int整型一维数组
*/
public int[] LIS (int[] arr) {
int[] tail = new int[arr.length];
int[] dp = new int[arr.length];
int len = 0;
//构建dp,dp记录每一位最长升子序列长度
for(int i = 0;i<arr.length;i++){
//当tail中为空时,或要加入的元素大于tail当前最大值,则直接加入
//tail之前的元素也成为其的升子序列
if(i==0||tail[len-1]<arr[i]){
tail[len++]=arr[i];
dp[i]=len;
}
//否则,要寻找之前哪些元素可以是当前元素的升子序列部分(即寻找第一个大于arr[i]的值位置)
else{
//要传入len,因为tail的length并不是目前已存储了多少元素
int index = search(tail,len,arr[i]);
//为什么是直接赋值
/*
将该位置的元素替换为arr[i]arr[i]arr[i],
因为在长度相同的情况下,当前值越小,则后面出现更长子序列的概率越大。
*/
tail[index] = arr[i];
dp[i] = index+1;
}
}
//与当前dp中存储与len匹配对应的元素即是升子序列一部分
//为什么这样出来的序列最小,同len,index越大对应数值越小,从后往前
int[] res = new int[len];
for(int i = arr.length-1;i>=0;i--){
if(dp[i]==len){
res[--len] = arr[i];
}
}
return res;
}
private int search(int[] tail,int len, int num){
int low=0,high=len-1;
while(low<high){
int mid = (low+high)/2;
//不排除大的故high的指向mid(即此mid指向可能是我们需要的值)
//排除所有小的故low指向mid要移动
if(tail[mid]>=num)
high=mid;
else
low=mid+1;
}
return high;
}
}
注意处理0,1特殊情况
范围;i<=x/2+1,加1不能省略
注意二分查找的范围控制
public int search (int[] nums, int target) {
// write code here
int l = 0,r = nums.length-1;
while(l<=r){//等号
int mid = (l+r)/2;
if(nums[mid]==target)return mid;
if(nums[mid]>=nums[l]){//前段有序
if(target>=nums[l]&&target<nums[mid])
r = mid-1;
else
l = mid+1;
}
//后半段有序
else{
if(target<=nums[r]&&target>nums[mid])
l = mid+1;
else
r = mid-1;
}
}
return -1;
}
从右往左存储目前最小值,计算的总是当前范围内的最小值,故一定符合先买后卖原则
public int maxProfit (int[] prices) {
// write code here
int minprice = Integer.MAX_VALUE;
int ans = 0;
for(int i = 0;i<prices.length;i++){
if(prices[i]<minprice){
minprice = prices[i];
}
if(prices[i]-minprice>ans)
ans = prices[i]-minprice;
}
return ans;
}
每次递归传入当前一组成的字符串,和可以继续组的字符串
public ArrayList<String> Permutation(String str) {
ArrayList<String> result = new ArrayList();
if(str==null||str.length()==0)
return null;
newString(str,"",result);
return result;
}
public void newString(String str,String newstr,ArrayList<String> result){
if(str.length()==0){
if(!result.contains(newstr.toString()))
result.add(newstr.toString());
return ;
}
for(int i = 0;i<str.length();i++){
newString(str.substring(0,i)+str.substring(1+i,str.length()),newstr+str.charAt(i),result);
}
}
可以用递归法解决。将一个岛屿的起点进行递归,经历过的填都改为0
// write code here
int sum = 0;
//每遇到一个不为零的值,则说明出现一个岛屿sum++
//从此点为起点,利用递归将此岛屿上的错油都置为0,即记录过就删除
for(int i = 0;i<grid.length;i++){
for(int j = 0;j<grid[0].length;j++){
if(grid[i][j]=='1'){
sum++;
dfs(grid,i,j);
}
}
}
return sum;
}
private void dfs(char[][] grid,int i,int j){
if(i<0||i>=grid.length||j<0||j>=grid[0].length||grid[i][j]=='0')
return;
grid[i][j] = '0';
dfs(grid,i-1,j);
dfs(grid,i+1,j);
dfs(grid,i,j-1);
dfs(grid,i,j+1);
}
}
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 返回表达式的值
* @param s string字符串 待计算的表达式
* @return int整型
*/
public int solve (String s) {
// write code here
Stack<Integer> snum = new Stack<Integer>();
Stack<Character> sop = new Stack<Character>();
Map<Character,Integer> map = new HashMap<Character,Integer>();
//建立优先级关系
map.put('-',1);
map.put('+',1);
map.put('*',2);
map.put('(',0);
int index = 0;
while(index<s.length()){
//当前位数字
if(s.charAt(index)<='9'&&s.charAt(index)>='0'){
//因可能超过各位数字,故组合数组。直至找到非数字字符
String str = "";
while(index<s.length()&&s.charAt(index)<='9'&&s.charAt(index)>='0'){
str += s.charAt(index++);
}
int sum = Integer.parseInt(str);
//将数组入栈
snum.push(sum);
}
else{
//计算字符为空直接入栈
if(sop.isEmpty())
sop.push(s.charAt(index));
//输入字符为(直接入栈
else if(s.charAt(index)=='(')
sop.push(s.charAt(index));
//输入字符为),找到一个匹配的(
else if(s.charAt(index)==')'){
//不是(就一致出栈计算
while(sop.peek()!='('){
int num = compute(snum.pop(),snum.pop(),sop.pop());
snum.push(num);
}
//最好将(出战
sop.pop();
}
//输入字符的优先级高于当前栈顶,直接入栈
else if(map.get(s.charAt(index))>map.get(sop.peek()))
sop.push(s.charAt(index));
else{
//输入字符的优先级低或等于当前栈顶,需计算
//特例情况,肯能遇见下一个字符是(则停止计算,其仅当)来临才消失。故优先及中加入了‘(’将其优先级设为最低
while(!sop.isEmpty()&&map.get(s.charAt(index))<=map.get(sop.peek())){
int num = compute(snum.pop(),snum.pop(),sop.pop());
snum.push(num);
}
//计算完成再将字符入栈
sop.push(s.charAt(index));
}
index++;
}
}
if(!sop.isEmpty()){
int num = compute(snum.pop(),snum.pop(),sop.pop());
snum.push(num);
}
return snum.pop();
}
private int compute(int num1, int num2,char op){
switch(op){
case'-':return num2-num1;
case'+':return num1+num2;
case'*':return num1*num2;
default:return Integer.MIN_VALUE;
}
}
}
前k个最大或最小就想到用堆排序
1、这里有几个重点,语法需要注意
//Map的遍历,对实体,key,value的分别遍历
for(Map.Entry<String,Integer> m : map.entrySet())
若key map.keySet()
若value map.valueSet()
2、如何对Map实体构建排序比较器Map.Entry<String,Integer>是重点
Comparator<Map.Entry<String,Integer>> com = new Comparator<Map.Entry<String,Integer>>(){
public int compare(Map.Entry<String,Integer> o1,Map.Entry<String,Integer> o2){
if(o1.getValue().equals(o2.getValue())){
return o2.getKey().compareTo(o1.getKey());
}
else{
return o1.getValue()-o2.getValue();
}
}
};
完成代码
public class Solution {
/**
* return topK string
* @param strings string字符串一维数组 strings
* @param k int整型 the k
* @return string字符串二维数组
*/
public String[][] topKstrings (String[] strings, int k) {
// write code here
String[][] res = new String[k][2];
if(k==0)
return new String[][]{};
//加入Map中,不断更新key
Map<String,Integer> map = new HashMap<String,Integer>();
for(int i = 0;i<strings.length;i++){
map.put(strings[i],map.getOrDefault(strings[i],0)+1);
}
//构建比较器
Comparator<Map.Entry<String,Integer>> com = new Comparator<Map.Entry<String,Integer>>(){
//值不同,值小的放前面;值同字典大的放前面
public int compare(Map.Entry<String,Integer> o1,Map.Entry<String,Integer> o2){
if(o1.getValue().equals(o2.getValue())){
return o2.getKey().compareTo(o1.getKey());
}
else{
return o1.getValue()-o2.getValue();
}
}
};
//构建顶堆
Queue<Map.Entry<String,Integer>> queue = new PriorityQueue<Map.Entry<String,Integer>>(com);
for(Map.Entry<String,Integer> m : map.entrySet()){
if(queue.size()<k){
queue.offer(m);
}
else{
if(com.compare(queue.peek(),m)<0){
queue.poll();
queue.offer(m);
}
}
}
//逆序放入
for(int i = k-1;i>=0;i--){
Map.Entry<String,Integer> m = queue.poll();
res[i][0]=m.getKey();
res[i][1]=m.getValue().toString();
}
return res;
}
}
char s = '' 错误写法不能为空字符
int转String :Integer.toString(num)
正弦转char注意要强制类型转换char ch =(char) ('A'+num-10)