diff --git a/Week_01/Algorithm.java b/Week_01/Algorithm.java new file mode 100644 index 00000000..00bf3070 --- /dev/null +++ b/Week_01/Algorithm.java @@ -0,0 +1,60 @@ + +class Solution { + public int climbStairs(int n) { + if(n <=2){ + return n; + } + int f1=1; + int f2=2; + int f3=3; + for(int i=3;i<=n;i++){ + f3= f1+f2; + f1= f2; + f2= f3; + } + return f3; + } +} + + +class Solution { + public int[] plusOne(int[] digits) { + for(int i=digits.length -1 ;i>=0; i--){ + digits[i]++; + digits[i] = digits[i]%10; + if(digits[i] != 0){ + return digits; + } + } + digits = new int[digits.length+1]; + digits[0]=1; + return digits; + } +} + +class Solution { + public int maxArea(int[] height) { + int i=0, j=height.length-1, res=0; + while(i deque = new LinkedList(); + int[] res = new int[nums.length - k + 1]; + for (int i = 0; i < nums.length; i++) { + while (!deque.isEmpty() && deque.peekLast() < nums[i]) { + deque.removeLast(); + } + deque.addLast(nums[i]); + + if (i >= k - 1) { + res[i - k + 1] = deque.peekFirst(); + //队列的第一个元素可能在上次窗口移动时已经被干掉了,所以要判断下 + //把移除窗口最左侧元素放到代码最后,这样就可以把index为2和index>2两种情况合并成一种情况处理 + if (deque.peekFirst() == nums[i - k + 1]) { + deque.removeFirst(); + } + } + } + return res; + } + + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap(); + for (int i = 0; i < nums.length; i++) { + if (map.containsKey(target - nums[i])) { + return new int[]{i, map.get(target - nums[i])}; + } + map.put(nums[i], i); + } + return new int[]{}; + } + + public List> threeSum(int[] nums) { + List> res = new ArrayList>(); + //基础校验,小于3 return + if (nums == null || nums.length < 3) { + return res; + } + //排序 + Arrays.sort(nums); + for (int i = 0; i < nums.length; i++) { + //如果nums[i]大于0,return + if (nums[i] > 0) { + return res; + } + //如果碰到重复,continue + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + int left = i + 1; + int right = nums.length - 1; + while (left < right) { + //如果三数之和等于0,设置res,L++, R--, 判断重复 + int sum = nums[i] + nums[left] + nums[right]; + if (sum == 0) { + res.add(Arrays.asList(nums[i], nums[left], nums[right])); + } + if (sum <= 0) { + left++; + //如果跟上一个数相同,继续向前一步 + //这里left < right容易忽视 + while (left < right && nums[left] == nums[left - 1]) { + left++; + } + } + if (sum >= 0) { + right--; + //这里判断下,避免right索引超界 + while (left < right && right < nums.length - 1 && nums[right] == nums[right + 1]) { + right--; + } + } + } + } + return res; + + } + +} diff --git a/Week_02/README.md b/Week_02/README.md index 50de3041..f7abcd6f 100644 --- a/Week_02/README.md +++ b/Week_02/README.md @@ -1 +1,12 @@ -学习笔记 \ No newline at end of file +## 算法知识总结 + +- 国庆假期在外面玩,基本没学习。国庆节后回来,已经完全没了状态,作业也是到10.14才补上。 +- 学习视频 + - hashmap做为常考点,比较熟悉。hashset是用hashmap实现的,这点之前没注意到 + - 熟悉了二叉搜索树(查询,添加,删除都是logN),二叉堆(堆顶查询O(1), 添加,删除logN)。类似这些数据结构,学习了容易忘,这次系统学习后希望不会忘 + - 图这块讲的比较少,其实这块还是比较感兴趣。之前有了解过图数据库,但是不够深入 +- 刷题 + - 二叉树的最近公共祖先: 巩固了下二叉树的后续遍历 + - 滑动窗口的最大值: 学习了单调队列这种数据结构,感觉比较巧妙 + - 两数之和:借助hashmap 解决问题 + - 三数之和: 这个算法看的时间挺长的,解法也比较巧妙。如果面试碰到,感觉不太好讲 diff --git a/Week_03/Algorithm.java b/Week_03/Algorithm.java new file mode 100644 index 00000000..153f17b5 --- /dev/null +++ b/Week_03/Algorithm.java @@ -0,0 +1,68 @@ + +//组合 +public List> combine(int n, int k){ + List> res = new ArrayList(); + if(k<=0 || n paths = new ArrayDeque(); + dfs(n,k,1,paths,res); + return res; + } + public void dfs(int n, int k, int begin,Deque paths, List> res){ + // 递归终止条件:path.size = k + if(paths.size() == k ){ + res.add(new ArrayList(paths)); + return; + } + for(int i=begin;i<=n;i++){ + paths.addLast(i); + //因为是组合,每下探一层i+1,避免有重复元素 + dfs(n,k,i+1,paths,res); + //递归恢复后,重置到递归前的状态,继续for循环 + paths.removeLast(); + } + + } + + + + +//全排列 + public List> permute(int[] nums) { + //res初始化 + List> res = new ArrayList(); + //校验 + if(nums.length == 0){ + return res; + } + //path链路中已使用标记下,这个used也是比较巧妙的 + boolean[] used = new boolean[nums.length]; + //paths初始化 + Deque paths = new ArrayDeque(); + dfs(nums,used,0,paths,res); + //dfs遍历 + return res; + } + + public void dfs(int[] nums, boolean[] used, int deepth, Deque paths, List> res){ + //退出条件 + if( deepth == nums.length){ + //这里注意,新建一个list,因为paths会被多个地方引用到,会被修改 + res.add(new ArrayList(paths)); + return; + } + //处理当前层 + for(int i=0;i 0){ + five--; + ten++; + }else{ + return false; + } + }else if(bill == 20){ + if(five > 0 && ten > 0 ){ + five--; + ten--; + }else if(five >= 3){ + five = five - 3; + }else{ + return false; + } + } + } + return true; + } + + + +//单词接龙1 +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if(wordList == null || wordList.size()==0){ + return 0; + } + //广度优先遍历,找最短路径 + //组织一个hashmap,key是带通配符的单词,示例:*og, d*g, do* + //然后使用队列层次遍历 + Map> patternMap = new HashMap(); + //记录访问过的节点,避免重复 + Set visitedWord = new HashSet(); + //所有单词的长度相同 + int wordLength = wordList.get(0).length(); + for(String word : wordList){ + for(int i=0;i matchPatternWords = patternMap.getOrDefault(wordPattern, new ArrayList()); + matchPatternWords.add(word); + patternMap.put(wordPattern,matchPatternWords); + } + } + + Queue queue = new LinkedList(); + //最短转换序列,是包含起始节点的,所以从1开始 + queue.add( new WordObj(beginWord,1)); + visitedWord.add(beginWord); + while( ! queue.isEmpty()){ + WordObj wordObj1 = queue.remove(); + int level = wordObj1.getLevel(); + String word1 = wordObj1.getWord(); + + for(int i=0;i matchPatternWords = patternMap.get(wordPattern); + if(matchPatternWords == null || matchPatternWords.size() == 0 ){ + continue; + } + for(String matchPatternWord : matchPatternWords ){ + if(matchPatternWord.equals(endWord)){ + return level+1; + } + if( ! visitedWord.contains(matchPatternWord)){ + visitedWord.add(matchPatternWord); + queue.add(new WordObj(matchPatternWord, level+1)); + } + } + } + } + return 0; + } + class WordObj { + private String word; + private int level; + + public WordObj(String word,int level){ + this.word = word; + this.level = level; + } + public String getWord(){ + return word; + } + public int getLevel(){ + return level; + } + } +} + + + +//单词接龙2 +class Solution { + public List> findLadders(String beginWord, String endWord, List wordList) { + //校验wordList是否包含endWord + if( ! wordList.contains(endWord)){ + return new ArrayList(); + } + //记录结果 + List> res = new ArrayList(); + //return bfs(beginWord,endWord,wordList); + //bfs + //因为要记录路径,所以队列元素类型是List + Queue> q = new LinkedList(); + //创建访问记录,避免重复访问(出现重复访问,路径肯定不是最短的,这里要最短路径) + Set visited = new HashSet(); + //创建set,获取下层节点(getNeighbours)时,判断是否存在于wordList + Set dict = new HashSet(); + dict.addAll(wordList); + //当前层是否存在最短路径,如果存在,当前层遍历完后就结束while循环 (所有最短路径都在同一层) + boolean isFound = false; + //添加首个元素 + List firstPath = new ArrayList(); + firstPath.add(beginWord); + q.add(firstPath); + visited.add(beginWord); + while( ! q.isEmpty()){ + //每层首个元素开始,计算size,然后for循环遍历当前层的元素 + int size = q.size(); + //当前层处理后,再统一放到visited集合 + Set subVisited = new HashSet(); + for(int i=0; i< size; i++){ + List path1 = q.remove(); + //获取末尾的元素 + String node1 = path1.get(path1.size()-1); + List neighbours = getNeighbours(node1,dict); + for(String neighbour : neighbours){ + //在所有的最短路径中,一个元素不可能同时出现在不同层 + if( ! visited.contains(neighbour)){ + subVisited.add(neighbour); + //匹配到结果 + if(neighbour.equals(endWord)){ + isFound = true; + path1.add(neighbour); + //拷贝元素,避免引用修改等问题 + res.add(new ArrayList(path1)); + }else{ + //在list中添加元素,等path1塞到队列后,再把末尾元素移除; + path1.add(neighbour); + } + q.add(new ArrayList(path1)); + //恢复状态,继续下一个neighbour处理 + path1.remove(path1.size()-1); + } + } + } + //当前层遍历完后,subVisited放到visited + visited.addAll(subVisited); + if(isFound){ + break; + } + } + return res; + } + + /** + * 获取所有相邻元素(字母相差一位的元素) + */ + private List getNeighbours(String word, Set dict ){ + List res = new ArrayList(); + for(char i='a';i<='z';i++){ + //word转char数组 + char[] chs = word.toCharArray() ; + for(int j=0;j