leetcode81. Search in Rotated Sorted Array II
- 题目意思是:根据某个值旋转数组,在新的数组中查找某个元素
- 输入的数组可能是排好序的,也可能是排序之后旋转的
旋转数组由中间数划分:一定有一个区间是顺序的,判断target比这个区间最小数小,比最大数大,则不在该区间中,改变l或者r。
public boolean search(int[] nums, int target) { if(null == nums||nums.length==0) return false; int l=0,r=nums.length-1; while(l<r){ int m=(l+r)/2; if(nums[m]==target) return true; if(nums[l]<nums[r]){//没有旋转 if(target>nums[m]){ l=m+1; }else{ r=m-1; } }else if(nums[l]>nums[r]){ if(nums[m]>=nums[l]){ if(target>nums[m]||target<nums[l]) { l=m+1; }else{ r=m-1; } }else{ if(target<nums[m]||target>nums[r]){ r=m-1; }else{ l=m+1; } } }else { l++; } } if(l==r && target==nums[l]) return true; else return false; }
leetcode90. Subsets ||
- 题目要求列举出所有的集合情况
- 分成两类:集合中有重复元素 集合中没有重复元素
- 无重复元素:先产生一个空的数组,然后每次将新产生的元素放到已有的列表中
有重复元素:先排序,记录一下每次改变的list个数,如果当前元素与上一个元素重复,则仅改变上一次循环产生的list,否则就都要进行处理
public List<List<Integer>> subsetsWithDup(int[] nums) { Arrays.sort(nums); List<List<Integer>> list= new ArrayList<List<Integer>>(); List templist= new ArrayList<Integer>(); list.add(new ArrayList<Integer>()); templist.add(nums[0]); list.add(templist); int count=1; for(int j=1;j<nums.length;j++){ int index=list.size(); int start=0; if(nums[j]==nums[j-1]) { start=index-count; } count=0; for(int i=start;i<index;i++){ List<Integer> temp =new ArrayList<Integer>(list.get(i)); temp.add(nums[j]); list.add(temp); count++; } } return list; }
leetcode105,106 Construct Binary Tree
- 题目要求根据前序/后序和中序遍历,重新构建二叉树
- 用递归的方法,前序遍历中第一个位置就是根节点,然后在中序遍历中找根节点所在的位置,从而分出根节点的左右两边。
- 记录左右两边的开始和结束的位置,以及左右两边要找的下一个根节点
- 以前序遍历为例,左边的下一个根节点,就在当前节点+1,右边的下一个根节点,就是当前节点+(当前根节点位置-start)+1
root.left=buildHelper(preStart+1,start,index-1,preorder,inorder);```
root.right=buildHelper(preStart+index-start+1,index+1,end,preorder,inorder);
leetcode 229. Majority Element(疑问:为什么c1,c2要减1)
- 题目要求将数组中出现次数大于1/3的数找出来
- 大于三分之一的数,一定少于等于2个,否则总数超过1
- 为了空间和时间的问题,设置两个数记录这两个数并用两个变量记录这两个数出现的次数
- 当前的数等于n1,则c1++;
- 当前的数等于n2,则c2++
- c1==0,则n1=当前数,c1=1
- c2==0.则n2=当前数,c2=1
- 否则 c1--,c2--
然后获得的n1,n2,就是出现最多的两个数,然后统计这两个数出现次数,若大于1/3,则添加到list中。
public List<Integer> majorityElement(int[] nums) { List<Integer> list =new ArrayList<Integer>(); if(null==nums||nums.length==0){ return list; } int n=nums.length; if(n==1){ list.add(nums[0]); return list; } int n1=nums[0]; int n2=0; int c1=1,c2=0; for(int i=1;i<n;i++){ if(nums[i]==n1){ c1++; }else if(nums[i]==n2){ c2++; }else if(c1==0){ n1=nums[i]; c1=1; }else if(c2==0){ n2=nums[i]; c2=1; }else{ c1--; c2--; } } c1=0; c2=0; for(int i=0;i<n;i++){ if(nums[i]==n1) c1++; else if(nums[i]==n2) c2++; } if(c1>n/3.0) list.add(n1); if(c2>n/3.0) list.add(n2); return list; }
leetcode 287. Find the Duplicate Number
- 根据题目特征,n+1个整数的范围在1-n中间
- 根据鸽巢原理,先统计1-n/2的数字出现次数,若大于一半,就认为有重复的数字,否则重复数字在另外一部分
- 用二分法来解决该问题
另一种算法flody判圈算法(该算法很重要,腾讯笔试题中曾出现)
public int findDuplicate(int[] nums) { int start=1; int end=nums.length-1; int index=0; while(start<end){ int count=0; index=(start+end)/2; for(int i=0;i<nums.length;i++){ if(nums[i]<=index){ count++; } } if(count>index){ end=index; }else{ start=index+1; } } return start; }
leetcode 3. Longest Substring Without Repeating Charachters
- 总体思路确定起点,往后遍历,当遇到重复字符时,提取重复字符所在位置+1,为开始位置
当没有重复字符时,把当前字符存储到Map中
public int lengthOfLongestSubstring(String s) { if (s.length()==0) return 0; HashMap<Character, Integer> map = new HashMap<Character, Integer>(); int max=0; for (int i=0, j=0; i<s.length(); ++i){ if (map.containsKey(s.charAt(i))){ j = Math.max(j,map.get(s.charAt(i))+1); } map.put(s.charAt(i),i); max = Math.max(max,i-j+1); } return max; }
leetcode 15. 3sum(很好)
- 3个数相加,和需要为某一个值,重要的是考虑重复问题
- for循环从第一个元素遍历,后面就是2Sum问题
- 设置左右两个指针,如果当前元素与下一个元素相同,则i++
- 如果当前左右两个指针所指的数字和是目标值,就加入list,同时左右指针都往中间移动
每次循环过程中要判断左右两个指针前后是否有重复元素
public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> list =new ArrayList<List<Integer>>(); Arrays.sort(nums); for(int i=0;i<nums.length-2;i++){ if(i>0&&nums[i]==nums[i-1]) { continue; } int target =-nums[i]; int start=i+1,end=nums.length-1; while(start<end){ if(nums[start]+nums[end]==target){ list.add(Arrays.asList(nums[i],nums[start],nums[end])); start++; end--; while(start<end&&nums[start]==nums[start-1])start++; while(start<end&&nums[end]==nums[end+1]) end--; }else if(nums[start]+nums[end]>target){ end--; }else{ start++; } } } return list; }
leetcode 5. Longest Palindromic Substring
- 给出字符串,找出最长的回文字串
- 方法有4种,暴力破解、动态规划、中心扩展、增加字符Manacher算法
- 暴力破解,遍历找出所有的子串,判断子串是否是回文字符串。时间复杂度为:n*n*n
- 动态规划:如果字符串sj是回文字符串,则(s+1,j-1)也是回文字符串。定义一个与字符串长度相同的二维数组,用来记录ij字符串是否是回文字符串。flag[i][i]一定为回文字符串,然后判断flag[i][i+1]是否是回文,再判断回文字符串长度大于等于3,以0起始位置开始,进行判断。时间复杂度为n*n
- 中心扩展方法:分奇数和偶数,都从i=0为中心点开始,奇数:s(i-1,i+1)相同,偶数s(i,i+1)相同,不断往外扩展。总体是一个for循环,里面一个while循环。时间复杂度为:n*n
为了解决中心扩展方法分奇偶的弊端,在字符串中间添加特殊字符,再以同样的方法遍历,时间复杂度为n
public String longestPalindrome(String s) { if(null==s ||s.length()<=1) return s; int len =s.length(); boolean [][] flag =new boolean[len][len]; String result =""; int maxlen=1; int start=0; for(int i=0;i<len;i++){ flag[i][i]=true; if(i<len-1&&s.charAt(i)==s.charAt(i+1)){ flag[i][i+1]=true; maxlen=2; start=i; } } for(int i=3;i<=len;i++){ for(int j=0;j<=len-i;j++){ int end =j+i-1; if(s.charAt(j)==s.charAt(end)&&flag[j+1][end-1]==true){ flag[j][end]=true; start=j; maxlen=i; } } } if(maxlen>=2){ return s.substring(start,start+maxlen); }else{ return s.charAt(0)+""; } }
leetcode 19. Remove Nth Node From End of List
- 题目意思是:删除链表的倒数第n个数,且只能遍历一次,无法先遍历一遍获取链表的长度
- 设置两个指针,快指针先走n步,如果当时已经到末尾,则删除的就是第一个元素。否则就快慢指针一起走,直到快指针到达末尾后,慢指针当前的位置,就是倒数第n个元素的位置
使用 p.next = p.next.next来删除某个元素
public ListNode removeNthFromEnd(ListNode head, int n) { ListNode f =head; ListNode s =head; for(int i=0;i<n;i++){ f=f.next; } while(f==null){ head=head.next; return head; } while(f.next!=null){ f=f.next; s=s.next; } s.next=s.next.next; return head; }
leetcode 22. Generate Parentheses
- 给出n个括号,写出所有的合法的括号组合
- 这个题跟验证合法性不同,运用的是深度优先算法dfs
- 即当左右两边括号数目都为0时,将当前的字符串加入list中。还要考虑左边大于右边的情况,这样直接返回
- 如果左边大于0,则添加(括号
如果右边大于0,则添加)括号
public ArrayList<String> generateParenthesis(int n) { ArrayList<String> res = new ArrayList<String>(); String item = new String(); if (n<=0) return res; dfs(res,item,n,n); return res; } public void dfs(ArrayList<String> res, String item, int left, int right){ if(left > right)//deal wiith ")(" return; if (left == 0 && right == 0){ res.add(new String(item)); return; } if (left>0) dfs(res,item+'(',left-1,right); if (right>0) dfs(res,item+')',left,right-1); }
leetcode 31. Next Permutation
- 题目的意思是:给出一个数字序列,找出下一个比当前数字序列大的最小的排列
- 解决思路:从后往前找,如果当前数字比后面的数字小,则交换,同时将后面的数据进行升序排列,保证首先找到的数字一定是后面所有数字中最小的。
如果没有,则将当前位置开始到结尾的数字序列进行排序。两重for循环
public void nextPermutation(int[] nums) { for(int i=nums.length-2;i>=0;i--){ for(int j=i+1;j<nums.length;j++){ if(nums[i]<nums[j]){ int temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; Arrays.sort(nums,i+1,nums.length); return; } } Arrays.sort(nums,i,nums.length); } }
leetcode 94. Binary Tree Inorder Traversal
- 给一个二叉树,输出它的中序遍历
- 迭代的写法是:用栈的结构保存,先往左找到最底层的左叶子节点,然后把值添加到list中,然后开始遍历右边。
因为不熟悉树的遍历,所以值得学习
public List<Integer> inorderTraversal(TreeNode root) { List<Integer> list = new ArrayList<Integer>(); Stack<TreeNode> stack = new Stack<TreeNode>(); TreeNode cur =root; while(cur!=null || !stack.isEmpty()){ while(cur!=null){ stack.add(cur); cur = cur.left; } cur=stack.pop(); list.add(cur.val); cur = cur.right; } return list; }
递归的方法
public List < Integer > inorderTraversal(TreeNode root) { List < Integer > res = new ArrayList < > (); helper(root, res); return res; } public void helper(TreeNode root, List < Integer > res) { if (root != null) { if (root.left != null) { helper(root.left, res); } res.add(root.val); if (root.right != null) { helper(root.right, res); } } }
leetcode 96. Unique Binary Search Trees
- 题目:给出n个自然数,算出所有可能的二叉树结构数目
- 思路:G(n) = F(1,n)+F(2,n)+F(3,n)+…..+F(n,n)
- G(n)是n个数的二叉树个数,F(1,n)是以1为根节点总共n个节点的二叉树的数目
- F(i,n)=G(i-1)*G(n-i)
- 即G(n) =G(0)G(n-1)+G(1)G(n-2)+….+G(n-1)G(0)
- 使用递归的方法很简单,但是会超时
使用迭代的方法,用数组记录计算结果
public int numTrees(int n) { int [] nums =new int [n+1]; nums[0] = 1 ; nums[1] = 1 ; for(int i=2;i<=n;i++){ for(int j=0; j<i ;j++){ nums[i]=nums[i]+nums[j]*nums[i-j-1]; } } return nums[n]; }