目录
复杂链表的复制
题目
题解
思路:使用哈希表,key为原节点的引用,value为新节点的引用
代码:
public Node copyRandomList(Node head) {
Map<Node,Node> map=new HashMap<>();
Node cur=head;
while(cur!=null){
Node node=new Node(cur.val);
map.put(cur,node);
cur=cur.next;
}
cur=head;
while(cur!=null){
map.get(cur).next=map.get(cur.next);
map.get(cur).random=map.get(cur.random);
cur=cur.next;
}
return map.get(head);
}
二叉搜索树与双向链表
题目
题解
代码:
public Node pre=null;
public Node head=null;
public Node treeToDoublyList(Node root) {
if(root==null) return null;
inOrder(root);
head.left=pre;
pre.right=head;
return head;
}
public void inOrder(Node cur){
if(cur==null) return;
inOrder(cur.left);
cur.left=pre;
if(pre!=null){
pre.right=cur;
}else {
head=cur;
}
pre=cur;
inOrder(cur.right);
}
序列化二叉树
题目
题解
思路:采用先序遍历的方式对树进行序列化,遇到空的节点用None来代替,在反序列化时也是采用先序遍历的方式,遇到None就代表当前节点为空,否则构造其左右子树
代码:
public String serialize(TreeNode root) {
String ret="";
return serializeChild(root,ret);
}
public String serializeChild(TreeNode root, String str){
if(root==null){
str+="None,";
}else {
str+=String.valueOf(root.val)+",";
str=serializeChild(root.left,str);
str=serializeChild(root.right,str);
}
return str;
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] ss=data.split(",");
List<String> list=new ArrayList<>(Arrays.asList(ss));
return deserializeChild(list);
}
public TreeNode deserializeChild(List<String> list){
if(list.get(0).equals("None")){
list.remove(0);
return null;
}
TreeNode root=new TreeNode(Integer.valueOf(list.get(0)));
list.remove(0);
root.left=deserializeChild(list);
root.right=deserializeChild(list);
return root;
}
字符串排列
题目
题解
代码:
List<String> ret;
boolean[] vis;
public String[] permutation(String s) {
ret=new ArrayList<>();
char[] str=s.toCharArray();
Arrays.sort(str);
int n=str.length;
vis=new boolean[n];
StringBuffer sb=new StringBuffer();
dfs(str,0,n,sb);
String[] res=new String[ret.size()];
for(int i=0;i<res.length;i++){
res[i]=ret.get(i);
}
return res;
}
public void dfs(char[] str,int i,int n,StringBuffer sb){
if(i==n){
ret.add(sb.toString());
return;
}
for(int j=0;j<n;j++){
if(vis[j] || (j>0 && !vis[j-1] && str[j-1]==str[j])){
continue;
}
vis[j]=true;
sb.append(str[j]);
dfs(str,i+1,n,sb);
sb.deleteCharAt(sb.length()-1);
vis[j]=false;
}
}
数组中出现次数超过一半的数字
题目
题解
代码:
public int majorityElement(int[] nums) {
int hp=nums[0];
int count=1;
for(int i=1;i<nums.length;i++){
if(nums[i]==hp){
count++;
}else if(count==0){
hp=nums[i];
count=1;
}else{
count--;
}
}
return hp;
}
最小的k个数
题目
题解
思路:基于快排的思想,经过依次划分后,会得到一个基准arr[i],基准的左侧区间为[l,i-1],基准的右侧区间为[i+1,r],判断k与i的关系
- 如果k==i,说明arr[i]是第k+1个数,直接返回数组前k个数即可
- 如果k<i,说明第k+1个数在左区间中,递归排序左区间
- 如果k>i,说明第k+1个数在右区间中,递归排序右区间
代码:
public int[] getLeastNumbers(int[] arr, int k) {
if(k>=arr.length) return arr;
return quickSort(arr,0,arr.length-1,k);
}
private int[] quickSort(int[] arr,int l,int r,int k){
int i=l;
int j=r;
while(i<j){
while(i<j && arr[j]>=arr[l]) j--;
while(i<j && arr[i]<=arr[l]) i++;
swap(arr,i,j);
}
swap(arr,i,l);
if(i>k) return quickSort(arr,l,i-1,k);
if(i<k) return quickSort(arr,i+1,r,k);
return Arrays.copyOf(arr,k);
}
private void swap(int[] arr,int i,int j){
int tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
数据流中的中位数
题目
题解
具体步骤:
step1:创建大根堆用来维护数组中较小的一半元素,创建小根堆用来维护数组中较大的一半元素
step2:当数组元素个数为奇数个时,两个堆的元素数量一定是相差1的,于是我们规定让大根堆中多存储一个元素,因此当数组个数为奇数个时,中位数就是大根堆的堆顶元素
step3:先将数据流中的数存入大根堆,然后将大根堆的堆顶元素弹出放到小根堆中,这样就保证了大根堆中始终存储的是数组中较小的一半元素,小根堆中存储的是较大的一般元素,在step2中规定大根堆中元素应该是大于等于小根堆中的元素的,因此因此需要再比较二者的长度,若是小顶堆长度小于大顶堆,需要从大顶堆中弹出最小值到大顶堆中进行平衡
step4:取中位数时,如果大根堆的元素个数比小根堆的元素多,说明一共有奇数个元素,直接返回大根堆的堆顶元素即可,如果两个堆中的元素个数相等,返回两个堆顶元素的平均值
private PriorityQueue<Integer> minQ;//大根堆,存储较小的一半元素
private PriorityQueue<Integer> maxQ;//小根堆,存储较大的一半元素
public MedianFinder() {
minQ=new PriorityQueue<>((a,b)->(b-a));
maxQ=new PriorityQueue<>();
}
public void addNum(int num) {
minQ.add(num);
maxQ.add(minQ.poll());
if(minQ.size()<maxQ.size()){
minQ.add(maxQ.poll());
}
}
public double findMedian() {
if(minQ.size()>maxQ.size()){
return 1.0*minQ.peek();
}else {
return (minQ.peek()+maxQ.peek())/2.0;
}
}
连续子数组的最大和
题目
题解
代码:
public int maxSubArray(int[] nums) {
int pre=nums[0];
int ret=nums[0];
for(int i=1;i<nums.length;i++){
int sum=Math.max(pre+nums[i],nums[i]);
ret=Math.max(sum,ret);
pre=sum;
}
return ret;
}
1~n整数中1出现的次数
题目
题解
代码:
public int countDigitOne(int n) {
if(n<1) return 0;
int cur=n%10;
int low=0;
int high=n/10;
int base=1;
int ret=0;
while(cur!=0 || high!=0){
if(cur>1){
ret+=(high+1)*base;
}else if(cur==1){
ret+=high*base+low+1;
}else if(cur<1){
ret+=high*base;
}
low+=cur*base;
base*=10;
cur=high%10;
high=high/10;
}
return ret;
}