题目描述:
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
import java.util.*;
public class Solution {
public int FirstNotRepeatingChar(String str) {
if(str==null||str.length()==0) return -1;
Map<Character,Integer> map = new HashMap<>();
char[] c = str.toCharArray();
for(int i=0;i<c.length;i++){
if(map.containsKey(c[i])){
int time = map.get(c[i]);
time++;
map.put(c[i],time);
}else{
map.put(c[i],1);
}
}
for(int j=0;j<c.length;j++){
if(map.get(c[j])==1){
return j;
}
}
return -1;
}
}
题目描述:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
import java.util.*;
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
RandomListNode cur = pHead;
Map<RandomListNode,RandomListNode> map = new HashMap<>();
while(cur!=null){
map.put(cur,new RandomListNode(cur.label));
cur = cur.next;
}
cur = pHead;
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(pHead);
}
}
题目描述:
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
平衡二叉树:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1(求平衡的问题转化成求二叉树高度问题)
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
return caculateHightByRoot(root)!=-1;
}
public int caculateHightByRoot(TreeNode root){
if(root == null) return 0;
int leftHight = caculateHightByRoot(root.left);
if(leftHight==-1) return -1;
int rightHight = caculateHightByRoot(root.right);
if(rightHight==-1) return -1;
if(Math.abs(leftHight-rightHight)>1) return -1;
return Math.max(leftHight,rightHight)+1;
}
}
题目描述:(滑动窗口)
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
if(sum<3) return res;
int left = 1;
int right = 2;
int curSum = left + right;
while(left<right&&right<sum){
while(curSum>sum&&left<sum/2){
curSum = curSum - left;
left++;
}
if(curSum==sum) res.add(numAsList(left,right));
right++;
curSum = curSum + right;
}
return res;
}
public ArrayList<Integer> numAsList(int left,int right){
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i=left;i<=right;i++){
list.add(i);
}
return list;
}
}
题目描述:
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。(零填充)
import java.util.*;
public class Solution {
public boolean isContinuous(int [] numbers) {
if(numbers.length<=0) return false;
int zero=0;
for(int a:numbers){
if(a==0) zero++;
}
Arrays.sort(numbers);
for(int i=zero+1;i<numbers.length;i++){
zero=zero-(numbers[i]-numbers[i-1]-1);
if(zero<0||numbers[i]==numbers[i-1]) return false;
}
return true;
}
}
题目描述:
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
如果没有小朋友,请返回-1(约瑟夫问题),链表法
公式: Index = (Index+m-1)%list.size();
import java.util.*;
public class Solution {
public int LastRemaining_Solution(int n, int m) {
if(n==0||m==0) return -1;
LinkedList<Integer> list = new LinkedList<>();
for(int i=0;i<n;i++){
list.add(i);
}
int Index = 0;
while(list.size()!=1){
Index = (Index+m-1)%list.size();
list.remove(Index);
}
return list.get(0);
}
}
题目描述:
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
public class Solution {
public int Sum_Solution(int n) {
return ((int)Math.pow(n,2)+n) >> 1;//除以2就是右移一位
}
}
题目描述:
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
public class Solution {
public int Add(int num1,int num2) {
int sum1,sum2;
do{
sum1=num1^num2;
sum2=(num2&num1)<<1;
num1=sum1;
num2=sum2;
}while(num2!=0);
return num1;
}
}
题目描述:
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
一.HashSet
特点:
1.HashSet中不能有相同的元素,可以有一个Null元素,存入的元素是无序的。
2.HashSet如何保证唯一性?
1).HashSet底层数据结构是哈希表,哈希表就是存储唯一系列的表,而哈希值是由对象的hashCode()方法生成。
2).确保唯一性的两个方法:hashCode()和equals()方法。
3.添加、删除操作时间复杂度都是O(1)。
4.非线程安全
二.LinkedHashSet
特点:
1.LinkedHashSet中不能有相同元素,可以有一个Null元素,元素严格按照放入的顺序排列。
2.LinkedHashSet如何保证有序和唯一性?
1).底层数据结构由哈希表和链表组成。
2).链表保证了元素的有序即存储和取出一致,哈希表保证了元素的唯一性。
3.添加、删除操作时间复杂度都是O(1)。
4.非线程安全
三.TreeSet
特点:
1.TreeSet是中不能有相同元素,不可以有Null元素,根据元素的自然顺序进行排序。
2.TreeSet如何保证元素的排序和唯一性?
底层的数据结构是红黑树(一种自平衡二叉查找树)
3.添加、删除操作时间复杂度都是O(log(n))
4.非线程安全
四.总结:
通过以上特点可以分析出,三者都保证了元素的唯一性,如果无排序要求可以选用HashSet;如果想取出元素的顺序和放入元素的顺序相同,那么可以选用LinkedHashSet。如果想插入、删除立即排序或者按照一定规则排序可以选用TreeSet。
import java.util.*;
public class Solution {
//Insert one char from stringstream
Set<Character> set = new LinkedHashSet<>();
public void Insert(char ch)
{
if(set.contains(ch)){
set.remove(ch);
}else
set.add(ch);
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce()
{
Iterator<Character> it = set.iterator();
if(it.hasNext()) return it.next();
return '#';
}
}
题目描述:
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
(中序遍历找第k小的数,二叉搜索树按中序遍历就是升序的排序了)
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
int index = 0;
TreeNode KthNode(TreeNode pRoot, int k)
{
if(pRoot!=null){
TreeNode node = KthNode(pRoot.left,k);
if(node!=null) return node;
index++;
if(index==k) return pRoot;
node = KthNode(pRoot.right,k);
if(node!=null) return node;
}
return null;
}
}
或者:
import java.util.ArrayList;
// {8,6,10,5,7,9,11},8
// null,5
public class Solution {
ArrayList<TreeNode> list = new ArrayList<>(); // (1)
TreeNode KthNode(TreeNode pRoot, int k)
{
addNode(pRoot);
if(k>=1 && list.size()>=k) {
return list.get(k-1);
}
return null;
}
// 中序遍历
void addNode(TreeNode cur) { // (2)
if(cur != null) {
addNode(cur.left);
list.add(cur);
addNode(cur.right);
}
}
}
收起
题目描述:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
if(pRoot == null){
return list;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(pRoot);
ArrayList<Integer> array = new ArrayList<>();
int start = 0;
int end = 1;
while(!queue.isEmpty()){
TreeNode node = queue.remove();
array.add(node.val);
start++;
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
if(start == end){
end = queue.size();
start = 0;
list.add(array);
array = new ArrayList<>();
}
}
return list;
}
}
题目描述:
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
如果map中含有指定的key,就返回该key对应的value,否则使用该方法的第二个参数作为默认值返回,下面是一个测试:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
import java.util.*;
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
Map<ListNode,Integer> map = new HashMap<>();
ListNode node = pHead;
while(node!=null){
map.put(node,map.getOrDefault(node,0)+1);
if(map.get(node)==2) return node;
node = node.next;
}
return null;
}
}
题目描述:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
import java.util.*;
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null){
return null;
}
ListNode root=new ListNode(0);
root.next=pHead;
ListNode preNode=root;
ListNode curNode=pHead;
while(curNode!=null){
if(curNode.next!=null&&curNode.val==curNode.next.val){
while(curNode.next!=null&&curNode.val==curNode.next.val){
curNode=curNode.next;
}
curNode = curNode.next;
preNode.next=curNode;
}else{
preNode=curNode;
curNode=curNode.next;
}
}
return root.next;
}
}
题目描述:
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode root)
{
if(root==null) return true;
return helper(root.left,root.right);
}
public boolean helper(TreeNode A,TreeNode B){
if(A==null&&B==null) return true;
if(A==null||B==null) return false;
return A.val==B.val&&helper(A.left,B.right)&&helper(A.right,B.left);
}
}
题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路
中序遍历特点:左中右;
假设该节点有右孩子,则找到右孩子的最左;
假设该节点没有右孩子,则应该找到父节点
如果该节点是父节点的左孩子,则就是父节点
如果该节点是父节点的右孩子,则是root节点
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode node)
{
if(node.right!=null){
TreeLinkNode cur = node.right;
while(cur.left!=null) cur = cur.left;
return cur;
}
while(node.next!=null){
if(node.next.left==node) return node.next;
node = node.next;
}
return null;
}
}
题目描述:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
import java.util.ArrayList;
public class Solution {
public String PrintMinNumber(int [] numbers) {
ArrayList<String> list = new ArrayList<>();
for(int a:numbers){
list.add(a+"");
}
list.sort((o1,o2)->{
String a1=o1+o2;
String a2=o2+o1;
return a1.compareTo(a2);
});
StringBuilder ans = new StringBuilder();
for(String x:list){
ans.append(x);
}
return ans.toString();
}
}
题目描述:
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
public class Solution {
public int cutRope(int target) {
if(target<2) return 0;
int[] dp = new int[target+1];
dp[2]=1;
for(int i=3;i<=target;i++){
for(int j=1;j<i;j++) dp[i]=Math.max(Math.max(j*dp[i-j],j*(i-j)),dp[i]);
}
return dp[target];
}
}
题目描述:
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<ArrayList<Integer>> Print(TreeNode root) {
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
if(root==null) return res;
Stack<TreeNode> s1 = new Stack<>();
Stack<TreeNode> s2 = new Stack<>();
int flag = 1;
s1.add(root);
ArrayList<Integer> temp = new ArrayList<Integer>();
while(!s1.isEmpty()||!s2.isEmpty()){
if(flag%2==1){
while(!s1.isEmpty()){
TreeNode node = s1.pop();
temp.add(node.val);
if(node.left!=null) s2.push(node.left);
if(node.right!=null) s2.push(node.right);
}
}
if(flag%2==0){
while(!s2.isEmpty()){
TreeNode node = s2.pop();
temp.add(node.val);
if(node.right!=null) s1.push(node.right);
if(node.left!=null) s1.push(node.left);
}
}
res.add(new ArrayList<Integer>(temp));
temp.clear();
flag++;
}
return res;
}
}
import java.util.*;
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
char[][] array = new char[rows][cols];
int index=0;
int x=0;
for(int i=0;i<matrix.length;i++){
if(index>=cols){
index=0;
x++;
}
array[x][index]=matrix[i];
index++;
}
StringBuilder stb = new StringBuilder();
for(int i=0;i<str.length;i++) stb.append(str[i]);
boolean[][] vis = new boolean[rows][cols];
for(int i=0;i<rows;i++)
for(int j=0;j<cols;j++)
if(getTureOrFalse(array,stb.toString(),i,j,vis,0)) return true;
return false;
}
public boolean getTureOrFalse(char[][] array,String word,int x,int y,boolean[][] vis,int index){
if(x<0||x>=array.length||y<0||y>=array[0].length||vis[x][y]==true) return false;
if(word.charAt(index)!=array[x][y]) return false;
if(index==word.length()-1) return true;
vis[x][y]=true;
boolean flag = getTureOrFalse(array,word,x+1,y,vis,index+1)||
getTureOrFalse(array,word,x-1,y,vis,index+1)||
getTureOrFalse(array,word,x,y+1,vis,index+1)||
getTureOrFalse(array,word,x,y-1,vis,index+1);
vis[x][y]=false;
return flag;
}
}
题目描述:
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
public class Solution {
private int sum=0;
public int movingCount(int threshold, int rows, int cols)
{
boolean[][] vis = new boolean[rows][cols];
int x=0,y=0;
getSum(rows,cols,x,y,vis,threshold);
return sum;
}
public int getS(int x,int y){
int res=0;
while(x!=0){
res=res+x%10;
x=x/10;
}
while(y!=0){
res=res+y%10;
y=y/10;
}
return res;
}
public void getSum(int rows,int cols,int x,int y,boolean[][] vis,int threshold){
if(x<0||y<0||x>=rows||y>=cols||vis[x][y]||getS(x,y)>threshold) return;
vis[x][y]=true;
sum++;
getSum(rows,cols,x+1,y,vis,threshold);
getSum(rows,cols,x-1,y,vis,threshold);
getSum(rows,cols,x,y+1,vis,threshold);
getSum(rows,cols,x,y-1,vis,threshold);
}
}
题目描述:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
import java.util.*;
public class Solution {
public ArrayList<String> Permutation(String str) {
char[] array = str.toCharArray();
ArrayList<String> list=new ArrayList<String>();
getRes(array,0,str.length(),list);
list=new ArrayList<String>(new HashSet<String>(list));
Collections.sort(list);
return list;
}
public void getRes(char[] a,int index,int length,ArrayList<String> list){
if(index==length-1) list.add(String.valueOf(a));
else{
for(int i=index;i<length;i++){
char temp=a[i];
a[i]=a[index];
a[index]=temp;
getRes(a,index+1,length,list);
temp=a[i];
a[i]=a[index];
a[index]=temp;
}
}
}
}
题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字(归并排序)
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1
输入
复制
1,2,3,4,5,6,7,0
输出
复制
7
public class Solution {
private long sum=0;
public int InversePairs(int [] array) {
int l=0;
int r=array.length-1;
divide(l,r,array);
return (int)(sum%1000000007);
}
public void divide(int l,int r,int [] array){
if(l==r) return;
int mid=(l+r)>>1;
divide(l,mid,array);
divide(mid+1,r,array);
merge(l,mid,r,array);
}
public void merge(int l,int mid,int r,int [] array){
int i=l;
int j=mid+1;
int[] temp = new int[r-l+1];
int index=0;
while(i<=mid&&j<=r){
if(array[i]>array[j]){
temp[index++]=array[j++];
sum=sum+mid-i+1;
}else{
temp[index++]=array[i++];
}
}
while(i<=mid) temp[index++]=array[i++];
while(j<=r) temp[index++]=array[j++];
index=0;
for(int k=l;k<=r;k++){
array[k]=temp[index++];
}
}
}
题目描述:
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.*;
public class Solution {
String Serialize(TreeNode root) {
if(root == null){
return "";
}
StringBuffer sb = new StringBuffer();
Serialize1(root,sb);
return sb.toString();
}
public void Serialize1(TreeNode root,StringBuffer sb){
if(root==null) {
sb.append("#!");
return;
}
sb.append(root.val+"!");
Serialize1(root.left,sb);
Serialize1(root.right,sb);
}
TreeNode Deserialize(String str) {
if("".equals(str)) return null;
String[] s = str.split("!");
return Deserialize1(s);
}
int index=-1;
TreeNode Deserialize1(String[] s){
index++;
if(!s[index].equals("#")){
TreeNode root=new TreeNode(Integer.parseInt(s[index]));
root.left=Deserialize1(s);
root.right=Deserialize1(s);
return root;
}
return null;
}
}