首页 文章 精选 留言 我的

精选列表

搜索[轻量版],共10000篇文章
优秀的个人博客,低调大师

Unity与Android交互方案优化版

本文适用对象有一定的Unity开发经验,会使用Unity有一定的Android开发经验,会使用AndroidStudio方案优势不需要引用unity下的class.jar不用在Unity的/Plugins/Android下放置AndroidManifest.xml文件Unity打包时PackageName不依赖于引用文件发布简单,只需要导出arr并直接拷贝到/Plugins/Android目录下即可使用,不用对文件做任何修改文章DEMO对应的IDE版本AndroidStudio 3.0 (2.1亲测通过)Unity 2017.2 (5.4.3亲测通过)流程Android部分创建AndroidStudio项目 首先我们打开AndroidStudio,并创建一个新项目,这里随便填写项目名、包名即可,因为这个项目我们后面并不会用到。SDK我们选最低的就行。Activity我们选个EmptyActivity也行。 然后我们点击「Finish」完成AndroidStudio项目创建。 创建和unity交互的Moudle项目 项目创建好以后开始我们的主菜,选中app然后新建一个moudle 更多unity2018的功能介绍请到paws3d爪爪学院查找。

优秀的个人博客,低调大师

深度学习最佳图书推荐(2019版)

你是否希望深入学习深度学习?如果你有这方面的意愿,请不要辜负我的整理工作,这是2019年最佳机器学习和深度学习书籍清单: ·Deep Learning by Ian Goodfellow, Yoshua Bengio, Aaron Courville ·Grokking Deep Learning by Andrew W.Trask ·Deep Learning with Pythonby Francois Chollet ·Hands-On Machine Learning with Scikit-Learn and TensorFlowby Aurélien Géron ·Reinforcement Learning: An Introduction (2nd Edition)by Richard S. Sutton, Andre

优秀的个人博客,低调大师

IntelliJ IDEA 2018.3 正式版发布!

IntelliJ IDEA 今年的最后一次大版本更新 2018.3 现已正式发布,值得关注的更新包括支持 Java 12、Git submodule、GitHub Pull Requests 和多行 TODO 注释等。 下面简单介绍一些更新内容! Java ● 支持即将发布的 Java 12,现已支持在 IDE 中预览 Raw String Literals (JEP 326) ● 改进 Java Stream API ● 增强 Data flow 功能 ● 可检测更多的重复项 编辑器 ● 支持多行 TODO 注释:只需从多行 TODO 注释的第二行开始添加缩进,IDE 就会将其与普通注释区分开来 ● 新的缩进状态栏显示当前文件中缩进的大小 ● 改进对 EditorConfig 的支持:EditorConfig 文件可支持语法高亮和代码补全 详细更新内容请查看发布公告和What’s new页面。 相关链接 IntelliJ IDEA 的详细介绍: https://www.oschina.net/p/intellij+idea IntelliJ IDEA 的下载地址: https://www.jetbrains.com/idea/download/#section=windows 温馨提示 有用户反馈升级至该版本后,部分插件不能使用,请谨慎! 原文发布时间为:2018-11-26 本文来自云栖社区合作伙伴“Java技术栈”,了解相关信息可以关注“Java技术栈”。

优秀的个人博客,低调大师

leetcode算法题学习Java版(2)

283.Move Zeros(移动零) 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组上操作,不能拷贝额外的数组。 尽量减少操作次数。 class Solution { public void moveZeroes(int[] nums) { int k = 0; for(int i = 0;i<nums.length;i++){ if(nums[i]!=0){ if(i!=k){ int temp = nums[k]; nums[k] = nums[i]; nums[i] = temp; } k++; } } } } 75.Sort Colors(颜色分类) 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 注意: 不能使用代码库中的排序函数来解决这道题。 示例:输入: [2,0,2,1,1,0]输出: [0,0,1,1,2,2]进阶: 一个直观的解决方案是使用计数排序的两趟扫描算法。 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 你能想出一个仅使用常数空间的一趟扫描算法吗? 解题思路,本题共三个元素,非常适合三路快排的方法,并且仅需扫描数组一遍即可完成排序 class Solution { public void sortColors(int[] nums) { int zero = -1; // nums[0...zero]==0 int two = nums.length; //nums[two...n-1]==2 for (int i = 0; i < two;) { if(nums[i]==0){ int temp = nums[++zero]; nums[zero] = nums[i]; nums[i++] = temp; }else if(nums[i]==1){ i++; }else{ assert nums[i]==2; int temp = nums[--two]; nums[two] = nums[i]; nums[i] = temp; } } } } 88.Merged sorted Array(合并有序数组) 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 说明: 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 示例: 输入: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6], n = 3 输出: [1,2,2,3,5,6] 解题思路:这道题解决很简单,但是最大效率的算法却也比较难想,很巧妙,暴力解法就是把两个数组合并,然后快排。但是参照了leetcode上别人的代码,效率更高,思路就是不断比较二者的最大值,把最大值放在nums1数组的最后,知道排序成功。 class Solution { public void merge(int[] nums1, int m, int[] nums2, int n) { int count = m + n - 1; m--; n--; while (m != -1 && n != -1) { nums1[count--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--]; } while (n != -1) { nums1[count--] = nums2[n--]; } } } 215.Kth Largest Element in an Array(数组中第K个最大的元素) 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 这道题很有趣,他的解法非常多,我也是在这道题感受到了自己与大佬之间的差距,就算用同一种解法,别人的代码也比我写的优雅的多。令人哭笑不得的是,自己写了半天的算法,其实运行下来比别人两行代码(Array.sort,调用jdk内置的函数)就搞定了还慢了很多倍。 解题思路:这道题用简单暴力的解法是非常容易的,同样是先对数组进行排序,最简单的办法是用jdk内置的Array.sort进行排序,然后从后往前取第k个元素,这种解法既简单,又由于jdk内置的快排效率非常高,在leetcode上这种解法只用了4ms,排名第二。当然更聪明的解法很多,例如,使用快排(分治算法),在快排的每一趟排完后,如果要找的k较大,则只对对应的一半继续进行快排,直到找到结果。还有使用堆的办法。 class Solution { public int findKthLargest(int[] nums, int k) { Queue<Integer> queue = new PriorityQueue<Integer>(); for (int i = 0; i < nums.length; i++) { if (i < k) { queue.add(nums[i]); } else if (queue.peek() < nums[i]) { queue.remove(); queue.add(nums[i]); } } return queue.peek(); } } class Solution { public int findKthLargest(int[] nums, int k) { int left = 0, right = nums.length - 1; while (true){ int pos = partition(nums, left, right); if(k - 1 == pos) return nums[pos]; else if(pos > k - 1) right = pos - 1; else left = pos + 1; } } public int partition(int[] nums, int left, int right){ int pivot = nums[left], l = left +1, r = right; while (l <= r){ if(nums[l] < pivot && nums[r] > pivot) swap(nums, l, r); if (nums[r] <= pivot) r--; if (nums[l] >= pivot) l++; } swap(nums, left, r); return r; } public void swap(int nums[], int left, int right){ int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; } } Two Sum II(两数之和) 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。 说明: 返回的下标值(index1 和 index2)不是从零开始的。 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 示例: 输入: numbers = [2, 7, 11, 15], target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 解题思路:这道题同样有多种思路,暴力解法是两次遍历该数组,找到相加等于target的索引,这种解法的时间复杂度是O(n^2)。利用二分法的思想来解这道题,时间复杂度是O(nlogn)。而利用对撞指针来解这道题,时间复杂度只有O(n),以下是对撞指针的解法。 class Solution { public int[] twoSum(int[] numbers, int target) { int i = 0,j = numbers.length-1; while(i<j){ if(numbers[i]+numbers[j]==target){ break; } if(numbers[i]+numbers[j]>target){ j--; } if(numbers[i]+numbers[j]<target){ i++; } } return new int[]{++i,++j}; } } 209.Minimum Size Subarray Sum(最小子数组) 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。 示例: 输入: s = 7, nums = [2,3,1,2,4,3] 输出: 2 解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。 进阶: 如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。 解题思路:该题使用滑动窗口法解决只需要O(n)的时间复杂度 public class MSSubarraySum { public int minSubArrayLen(int s, int[] nums) { int i = 0, j = -1; int sum = 0; int result = nums.length+1; while(i<nums.length){ if(j<nums.length-1&&sum<s){ sum+=nums[++j]; }else{ sum-=nums[i++]; } if(sum>=s) result = Math.min(result,j-i+1); } if(result == nums.length+1){ result = 0; } return result; } } 3.Longest Substring Without Repeating Characters(无重复字符的最小子串) 给定一个字符串,找出不含有重复字符的最长子串的长度。 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc",其长度为 3。 示例 2: 输入: "bbbbb" 输出: 1 解释: 无重复字符的最长子串是 "b",其长度为 1。 示例 3: 输入: "pwwkew" 输出: 3 解释: 无重复字符的最长子串是 "wke",其长度为 3。 请注意,答案必须是一个子串,"pwke" 是一个子序列 而不是子串。 解题思路:这道题同样是使用滑动窗口的思想去解是最佳的。该题需要记录每个字符出现的频率,因此初始化一个长度为256的freq数组,根据字符的ASCII码来每个字符出现的频率。根据频率来进行窗口的滑动。 class Solution { public int lengthOfLongestSubstring(String s) { int[] freq = new int[256]; for (int f = 0; f < freq.length; f++) { freq[f] = 0; } int i = 0, j = -1; int result = 0; while (i < s.length()) { if (j < s.length() - 1 && freq[s.charAt(j + 1)] == 0) { freq[s.charAt(++j)]++; }else{ freq[s.charAt(i++)]--; } result = Math.max(result, j - i + 1); } return result; } } Minimum Window Substring(最小覆盖子串) 给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。 示例: 输入: S = "ADOBECODEBANC", T = "ABC" 输出: "BANC" 说明: 如果 S 中不存这样的子串,则返回空字符串 ""。 如果 S 中存在这样的子串,我们保证它是唯一的答案。 解题思路:这道题我依然是使用滑动窗口的思想去解的,时间复杂度为O(2st),解题耗时较长,主要原因是每次都要遍历一遍结果集去判断结果是否正确,可以去参考leetcode 该题更好的解法。 class Solution { public String minWindow(String s, String t) { HashMap<Integer,Integer> target = new HashMap<>(); for(int i =0;i<t.length();i++){ if(target.get((int)t.charAt(i))==null){ target.put((int) t.charAt(i),1); }else{ int temp = target.get((int)t.charAt(i)); target.put((int) t.charAt(i),temp+1); } } int freq[] = new int[256]; for (int i = 0; i < freq.length; i++) freq[i] = 0; int i = 0, j = -1; int length = Integer.MAX_VALUE; String result = ""; while(i<s.length()){ if(j<s.length()-1&&!hasFound(freq,target)){ freq[s.charAt(++j)]++; }else{ freq[s.charAt(i++)]--; } if(hasFound(freq,target)){ if(length>j-i+1){ length = j-i+1; result = s.substring(i,j+1); } } } return result; } public static boolean hasFound(int[] arr1,HashMap<Integer,Integer> arr2){ // for(int i =0;i<arr2.length;i++){ // if(arr1[arr2[i]]<1) // return false; // } Iterator iter = arr2.entrySet().iterator(); while(iter.hasNext()){ Map.Entry<Integer,Integer> entry = (Map.Entry) iter.next(); if(arr1[entry.getKey()]<entry.getValue()){ return false; } } return true; } } 451.Sort Characters By Frequency(根据字符出现频率排序) 示例 1: 输入: "tree" 输出: "eert" 解释: 'e'出现两次,'r'和't'都只出现一次。 因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。 解题思路:这里我是用HashMap来解的,不过最后用了比较笨的办法来按顺序拼凑字符串。是通过类似选择排序的办法,每次比较map里的所有value值,将最大的值拿出来放在最前面。Leetcode上有更好的方法可以借鉴。 class Solution { public String frequencySort(String s) { Map<Character,Integer> map = new HashMap<>(); for(int i =0;i<s.length();i++){ map.put(s.charAt(i),map.getOrDefault(s.charAt(i),0)+1); } StringBuffer result = new StringBuffer(); int temp = -1; char tempKey=' '; int i = 0; while(i<s.length()){ for (Map.Entry<Character,Integer> entry:map.entrySet()) { if(temp<entry.getValue()){ tempKey = entry.getKey(); temp = entry.getValue(); } } map.remove(tempKey); while(temp>0){ result.append(tempKey); i++; temp--; } } return result.toString(); } } 15.3Sum(三数之和) 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 注意:答案中不可以包含重复的三元组。 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ] 解题思路:我用的是对撞指针的方式,遍历数组的过程中,对当前遍历的索引之后的数,采用对撞指针的方式,找到和等于0-nums【i】的两个数。我的代码略有瑕疵导致速度较慢,以下为leetcode上解题思路与我相同,但是做了细节优化的代码 class Solution { public List<List<Integer>> threeSum(int[] nums) { int len=nums.length; Arrays.sort(nums); List<List<Integer>> res = new ArrayList<>(); for(int i=0;i<len;i++){ if(nums[i]>0)break; //简化,如果>0则说明该三数之和不可能为0 if(i>0&&nums[i]==nums[i-1])continue; //去重 int target=0-nums[i]; int l=i+1,r=len-1; //此处必须对i后面的数字进行筛选,不能重复 while(l<r){ List<Integer> list=new ArrayList(); if(nums[l]+nums[r]==target){ list.add(nums[i]); list.add(nums[l]); list.add(nums[r]); res.add(list); while(r>l&&nums[l+1]==nums[l])l++; //这个地方改成l-1只会出现一个结果了 while(r>l&&nums[r]==nums[r-1])r--; l++;r--; }else if(nums[l]+nums[r]>target)r--; else l++; } } return res; } } 454.4SumII(四数相加II) 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。 为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。 例如: 输入: A = [ 1, 2] B = [-2,-1] C = [-1, 2] D = [ 0, 2] 输出: 2 解释: 两个元组如下: (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 解题思路:暴力解法为遍历四个数组所有情况,时间复杂度为O(n^4 )。本题我使用了查找表的方法,将数组A和B的所有和的情况置入查找表中,遍历C和数组D即可得到结果,时间复杂度为O(n^2) public int fourSumCount(int[] A, int[] B, int[] C, int[] D) { int result = 0; Map<Integer,Integer> map = new HashMap<>(); for(int i = 0;i<A.length;i++){ for(int j = 0;j<B.length;j++){ map.put(A[i]+B[j],map.getOrDefault(A[i]+B[j],0)+1); } } for(int i = 0;i<C.length;i++){ for(int j = 0;j<D.length;j++){ if(map.containsKey(0-C[i]-D[j])){ result+=map.get(0-C[i]-D[j]); } } } return result; } 206. Reverse Linked List 反转链表 反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 进阶: 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? 解题思路:对于链表题来说,一般不能直接操作链表节点的值,而是通过操作指针来改变链表。例如,扫描一遍链表,将值压入栈中,再第二次扫描链表,将值从栈中弹出,这种方式一般在面试的算法题中是不被允许的。因此,这道题我用了三个临时指针,只改变listNode的next指针的方向来改变链表。 public class ReverseLinkedList { public ListNode reverseList(ListNode head) { if(head == null) return head; ListNode pre = null, cur = head, next = head.next; while (cur != null){ cur.next = pre; pre = cur; cur = next; if(next!=null){ next = next.next; } } return pre; } } 92. Reverse Linked List II 反转链表 II 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 说明: 1 ≤ m ≤ n ≤ 链表长度。 示例: 输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL 这道题个人感觉还是挺难的,因为要处理的特殊情况较多,又不能直接更改节点的值,而是要通过指针来实现反转链表。这里还是以leetcode上大神写的更优美的代码为例吧 public ListNode reverseBetween_1(ListNode head, int m, int n) { if (head == null || m < 1 || m > n) return null; ListNode head1 = head; ListNode preTail = null;//需要逆置节点的前驱节点 //第一步:前进至第m节点,即行走m-1步;注意考虑m为1的情况,此时preTail=null int i = 1; while(head1 != null && i++ < m){ preTail = head1; head1 = head1.next; } //第二步:反转m->n节点 if(head1 == null) return head;//head1为null,不需要后翻转了 ListNode preNode = null; ListNode reverseListPreHead = head1; ListNode nextNode; while (head1 != null && m++ <= n) { nextNode = head1.next; head1.next = preNode; preNode = head1; head1 = nextNode; } //第三步:反转链表的头尾处理 reverseListPreHead.next = head1;//处理尾巴 if (preTail != null) {//处理头部 preTail.next = preNode; return head; }else{ return preNode;//若preTail为null,返回翻转链表段的最后一个节点 } } Remove Duplicates from Sorted List 删除排序链表中的重复元素 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 示例 1: 输入: 1->1->2 输出: 1->2 示例 2: 输入: 1->1->2->3->3 输出: 1->2->3 解题思路:这道题题意我理解错了,不知道是不是题目表达的问题,让我误以为要删除所有的不管是否相邻的具有重复值的节点。但看了leetcode上其他人的代码,都只是删除相邻的重复的节点。 if(head ==null) return null; if(head.next == null) return head; Set<Integer> set = new HashSet<>(); ListNode temp = new ListNode(-1); temp.next = head; while (temp!=null&&temp.next!=null){ ListNode next = temp.next; if(set.contains(next.val)) temp.next = temp.next.next; else{ set.add(next.val); temp = temp.next; } } return head; 86.Partition List 分隔链表 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。 你应当保留两个分区中每个节点的初始相对位置。 示例: 输入: head = 1->4->3->2->5->2, x = 3 输出: 1->2->2->4->3->5 解题思路:感觉链表的题都好难啊……但是看了别人的解法有感觉很简单,这道题的思路就是把小的和大的分别依次链起来,最后整合。 public ListNode partition(ListNode head, int x){ ListNode head1 = new ListNode(0); ListNode head2 = new ListNode(0); ListNode phead1 = head1; ListNode phead2 = head2; ListNode temp = head; while (temp!=null){ if(temp.val<x){ phead1.next = temp; temp = temp.next; phead1 = phead1.next; phead1.next = null; }else{ phead2.next = temp; temp = temp.next; phead2 = phead2.next; phead2.next = null; } } phead1.next = head2.next; head = head1.next; return head; } 328. Odd Even Linked List 奇偶链表 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。 请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。 示例 1: 输入: 1->2->3->4->5->NULL 输出: 1->3->5->2->4->NULL 示例 2: 输入: 2->1->3->5->6->4->7->NULL 输出: 2->3->6->7->1->5->4->NULL 说明: 应当保持奇数节点和偶数节点的相对顺序。 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。 解题思路:这道题和上一道题的解题思路基本一致。将奇偶数节点分别链起来,最后再整合即可。需要注意的是需要记录奇偶节点的首节点的位置,方便整合。 public ListNode oddEvenList(ListNode head) { ListNode temp = head; ListNode evenNode = new ListNode(-1); ListNode oddNode = new ListNode(-1); ListNode pEvenNode = evenNode; ListNode pfirOddNode = oddNode; int i = 1; while (temp != null){ if(i%2==0){ evenNode.next = temp; evenNode = evenNode.next; temp = temp.next; evenNode.next = null; }else { oddNode.next = temp; oddNode = oddNode.next; temp = temp.next; oddNode.next = null; } i++; } oddNode.next = pEvenNode.next; head = pfirOddNode.next; return head; } 2.Add Two Numbers 两数相加 给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 解题思路:不得不说看别人的代码都赏心悦目,相比之下自己的代码不知道是哪个弱智写的。这道题同样不难,两两相加,遇到某个数字位数不够了补0就可以了。这里还是以leetcode上大佬写的代码为例 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode next = new ListNode(0); ListNode result = next; int add = 0; while (l1 != null || l2 != null) { int l1val = (l1 != null) ? l1.val : 0; int l2val = (l2 != null) ? l2.val : 0; int value = l1val + l2val + add; add = value / 10; next.next = new ListNode(value % 10); next = next.next; l1 = (l1 != null) ? l1.next : null; l2 = (l2 != null) ? l2.next : null; } if (add > 0) { next.next = new ListNode(add); } return result.next; } 203. Remove Linked List Elements 移除链表元素 删除链表中等于给定值 val 的所有节点。 示例: 输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5 解题思路: 利用虚拟头结点,删除所有重复元素即可。我的代码有些小瑕疵,应该释放删除掉节点的内存空间。 public ListNode removeElements(ListNode head, int val) { ListNode dummyNode = new ListNode(0); dummyNode.next = head; ListNode cur = dummyNode; while (cur.next!=null){ if(cur.next.val==val) cur.next = cur.next.next; else cur = cur.next; } return dummyNode.next; } 82. Remove Duplicates from Sorted List II 删除排序链表中的重复元素 II 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。 示例 1: 输入: 1->2->3->3->4->4->5 输出: 1->2->5 示例 2: 输入: 1->1->1->2->3 输出: 2->3 解题思路:总感觉链表题都挺有难度的,可能是平常用的少的原因吧。这道题其实思路也很简单,就是遇到相同节点,就循环往下找下一个不同的节点,并链接。 public ListNode deleteDuplicates(ListNode head) { ListNode dummyHead = new ListNode(0); dummyHead.next = head; ListNode prev = dummyHead; while (prev.next != null) { ListNode cur = prev.next; if (cur.next == null || cur.val != cur.next.val) { prev = prev.next; continue; } while (cur.next != null && cur.next.val == cur.val) { cur.next = cur.next.next; } prev.next = cur.next; } return dummyHead.next; }

优秀的个人博客,低调大师

leetcode算法题学习Java版(1)

队列和广度优先搜索 岛屿的个数 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 https://leetcode-cn.com/explore/learn/card/queue-stack/217/queue-and-bfs/872/ 解题思路:广度优先,从某个为1的点开始,广度优先搜索他附近所有为1的点,将这些点的值改为2防止重复。计算有多少次将相邻的1改为2的次数,即为岛屿的次数。 class Solution { public int numIslands(char[][] grid) { if (grid == null || grid.length == 0 || grid[0].length == 0) return 0 ; int row = grid.length;//行数 int column = grid[0].length;//列数 int count = 0; for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { if (grid[i][j] == '1'){ count ++; combine(grid,i,j); } } } return count; } public static void combine(char[][] grid, int x, int y){ grid[x][y] = '2'; if (x > grid.length-1 && y > grid[0].length-1 ) { return; } if (x < grid.length-1 && grid[x+1][y] == '1') { //向下 combine(grid,x+1,y); } if (y < grid[0].length-1 && grid[x][y+1] == '1'){ //向右 combine(grid,x,y+1); } if (x > 0 && grid[x-1][y] == '1' ){ //向上 combine(grid,x-1,y); } if (y > 0 && grid[x][y-1] == '1') { //向左 combine(grid,x,y-1); } } } 打开转盘锁 你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。 锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。 列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。 字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。 https://leetcode-cn.com/explore/learn/card/queue-stack/217/queue-and-bfs/873/ 解题思路:将这道题看作是一道迷宫题,每次找一个数字当前能一步到的其他所有邻居数字,次数加1,所有邻居数字再找邻居数字的邻居数字,直到找到一个正确路径。 package com.ice.leetcode; import java.util.*; public class Solution { public static void main(String[] args) { String[] deadends = {"8887","8889","8878","8898","8788","8988","7888","9888"}; String target = "8888"; int count = openLock(deadends, target); System.out.println(count); } public static int openLock(String[] deadends, String target) { String start = "0000"; List<String> visited = new ArrayList<String>(); visited.add(start); Queue<String> queue = new LinkedList<String>(); int count = 0; queue.offer(start); while (!queue.isEmpty()) { int len = queue.size(); for (int i = 0; i < len; i++) { String top = queue.peek(); queue.poll(); List<String> neibors = findNeibors(top); for (String neibor:neibors) { if (target.equals(neibor)) { count++; return count; } if (findString(visited, neibor)) { continue; } if (!findString(Arrays.asList(deadends), neibor)) { visited.add(neibor); queue.offer(neibor); } } } count++; } return -1; } public static List<String> findNeibors(String s) { String temp = s; List<String> result = new ArrayList<>(); for (int i = 0; i < s.length(); i++) { char[] charTemp = temp.toCharArray(); charTemp[i] = String.valueOf((Integer.parseInt(String.valueOf(charTemp[i])) + 1) % 10).toCharArray()[0]; // charTemp[i] = (char) ((Integer.parseInt(String.valueOf(charTemp[i])) + 1) % 10); result.add(String.valueOf(charTemp)); charTemp[i] = String.valueOf((Integer.parseInt(String.valueOf(charTemp[i])) + 8) % 10).toCharArray()[0]; result.add(String.valueOf(charTemp)); } return result; } public static boolean findString(List<String> tofind, String s) { for (String temp : tofind) { if (s.equals(temp)) { return true; } } return false; } } 完全平方数 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 示例 1: 输入: n = 12 输出: 3 解释: 12 = 4 + 4 + 4. 示例 2: 输入: n = 13 输出: 2 解释: 13 = 4 + 9. https://leetcode-cn.com/explore/learn/card/queue-stack/217/queue-and-bfs/874/ 解题思路:这道题和上一道打开转盘锁思路基本一样,同样是使用广度优先,每遍历一层将count++。不同点在于,本题每层将一个数拆成一个完全平方数和另一个数之和,每次将另一个数加入队列,判断另一个数是否为完全平方数,否则,广度搜索他的下一层。 import static java.lang.Math.sqrt; class Solution { public int numSquares(int n) { int count = 0; Queue<Integer> queue = new LinkedList<>(); if(isSquare(n)){ return 1; } queue.offer(n); while(!queue.isEmpty()){ int len = queue.size(); for (int z=0;z<len;z++){ int top = queue.peek(); queue.poll(); for(int i=0;i<=sqrt(top);i++){ int m = top-i*i; if(isSquare(m)){ count +=2; return count; } if(m==top){ continue; } queue.offer(m); } } count++; } return count; } public static boolean isSquare(int n){ double temp = sqrt(n); int m = (int) temp; return m*m==n; } } 栈和深度优先搜索 有效的括号 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。 解题思路:本题较简单,利用堆栈,遇到右括号即一直出栈,判断括号是否匹配 class Solution { public boolean isValid(String s){ Stack<String> stack = new Stack<String>(); for(int i =0;i<s.length();i++){ String temp = s.substring(i,i+1); if(temp.equals("}")||temp.equals("]")||temp.equals(")")){ if(stack.empty()){ return false; } while (!stack.empty()){ String top = stack.peek(); stack.pop(); if((top.equals("{")||top.equals("[")||top.equals("("))){ if(!matchBrackets(top,temp)){ return false; }else { break; } } } }else { stack.push(temp); } } if(stack.isEmpty()){ return true; } return false; } public static boolean matchBrackets(String a,String b){ if( (a.equals("{")&&b.equals("}")) || (a.equals("[")&&b.equals("]")) || (a.equals("(")&&b.equals(")")) ){ return true; } return false; } } 每日温度 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高的天数。如果之后都不会升高,请输入 0 来代替。 例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。 提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的都是 [30, 100] 范围内的整数。 https://leetcode-cn.com/explore/learn/card/queue-stack/218/stack-last-in-first-out-data-structure/879/ 解题思路:本题利用栈,将气温不断入栈,判断下一个气温是否比栈顶的气温高,如果高,则不断出栈直到不比栈顶的温度高,如果,并逐个计算每个出栈元素与这个比他们高的气温的差值天数,最后将这个气温入栈,寻找下一个比他高的气温。直到栈空。 class Solution { public int[] dailyTemperatures(int[] temperatures) { Stack<Entry> stack = new Stack<Entry>(); int[] res = new int[temperatures.length]; for (int i = 0; i < temperatures.length; i ++) { if (stack.isEmpty()) { stack.push(new Entry(temperatures[i], i)); continue; } if (temperatures[i] <= stack.peek().val) stack.push(new Entry(temperatures[i], i)); else { int j = 1; while (!stack.isEmpty() && temperatures[i] > stack.peek().val) { Entry tmp = stack.pop(); res[tmp.index] = i - tmp.index; } stack.push(new Entry(temperatures[i], i)); } } return res; } private class Entry { public int val; public int index; public Entry(int val, int index) { this.val = val; this.index = index; } } } 逆波兰表达式求值 根据逆波兰表示法,求表达式的值。 有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 说明: 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 https://leetcode-cn.com/explore/learn/card/queue-stack/218/stack-last-in-first-out-data-structure/880/ 解题思路:本题很简单,不断入栈,遇到运算符就出栈前两位进行运算即可 class Solution { public int evalRPN(String[] tokens){ Stack<String> stack = new Stack<>(); for(int i =0;i<tokens.length;i++){ if(isSimbol(tokens[i])){ int temp1 = Integer.parseInt(stack.pop()); int temp2 = Integer.parseInt(stack.pop()); if(tokens[i].equals("+")){ stack.push(String.valueOf(temp1+temp2)); } if(tokens[i].equals("-")){ stack.push(String.valueOf(temp2-temp1)); } if(tokens[i].equals("*")){ stack.push(String.valueOf(temp1*temp2)); } if(tokens[i].equals("/")){ stack.push(String.valueOf(temp2/temp1)); } }else { stack.push(tokens[i]); } } return Integer.parseInt(stack.pop()); } public static boolean isSimbol(String s){ if(s.equals("+")||s.equals("-")||s.equals("*")||s.equals("/")){ return true; } return false; } }

优秀的个人博客,低调大师

[译]RabbitMQ教程C#版 - 主题

先决条件 本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672)。如果你使用不同的主机、端口或证书,则需要调整连接设置。 从哪里获得帮助 如果您在阅读本教程时遇到困难,可以通过邮件列表 联系我们。 主题 (使用.NET客户端) 在 教程[4] 中,我们改进了我们日志系统。我们用direct交换器替换了只能呆滞广播消息的fanout交换器,从而可以有选择性的接收日志。 虽然使用direct交换器改进了我们的系统,但它仍然有局限性 - 不能基于多个标准进行路由。 在我们的日志系统中,我们可能不仅要根据日志的严重性订阅日志,可能还要根据日志分发源来订阅日志。或许您可能从 unix syslog 工具中了解过这种概念,syslog 工具在路由日志的时候是可以既基于严重性(info/warn/crit...)又基于设备(auth/cron/kern...)的。 这种机制会给我们带来极大的灵活性 - 我们可以仅监听来自cron的关键错误日志,与此同时,监听来自kern的所有日志。 要在我们的日志系统中实现这一特性,我们需要学习更复杂的topic交换器。 Topic交换器 发送到topic交换器的消息不能随意指定routing key,它必须是一个由点分割的单词列表,这些单词可以是任意内容,但通常会在其中指定一些与消息相关的特性。请看一些合法的路由键示例:stock.usd.nyse,nyse.vmw,quick.orange.rabbit,路由键可以包含任意数量的单词,但不能超过255个字节的上限。 binding key也必须是相同的形式,topic交换器的背后逻辑与direct交换器类似 - 使用指定路由键发送的消息会被分发到与其绑定键匹配的所有队列中。不过对于绑定键来说,有两个重要的特殊情况需要注意: *(星号)可以代替一个单词。 #(哈希)可以代替零个或多个单词。 下图示例是对上述内容最简单的解释: 在这个示例中,我们打算发送的消息全是用来描述动物的,这些消息会使用由三个单词(两个点)组成的路由键来发送。在路由键中,第一个单词用来描述行动速度、第二个是颜色、第三个是物种,即:<speed>.<colour>.<species>。 我们创建了三个绑定:Q1绑定了键.orange.,Q2绑定了键*.*.rabbit和lazy.#。 这些绑定可以被概括为: Q1对所有橙色的动物感兴趣。 Q2对兔子以及所有行动缓慢的动物感兴趣。 路由键为quick.orange.rabbit的消息会被发送到这两个队列,消息lazy.orange.elephant也会被发送到这两个队列。另外,quick.orange.fox只会进入第一个队列,lazy.brown.fox只会进入第二个队列。lazy.pink.rabbit只会被发送到第二个队列一次,尽管它匹配了两个绑定(避免了消息重复)。quick.brown.fox没有匹配的绑定,因此它将会被丢弃。 如果我们打破约定,发送使用一个或四个单词(例如:orange和quick.orange.male.rabbit)作路由键的消息会发生什么?答案是,这些消息因为没有匹配到任何绑定,将被丢弃。 但是,另外,例如路由键为lazy.orange.male.rabbit的消息,尽管它有四个单词,也会匹配最后一个绑定,并将被发送到第二个队列。 Topics 交换器 topic交换器的功能是很强大的,它可以表现出一些其他交换器的行为。 当一个队列与键#(哈希)绑定时, 它会忽略路由键,接收所有消息,这就像fanout交换器一样。 当特殊字符*(星号)和#(哈希)未在绑定中使用时,topic交换器的行为就像direct交换器一样。 组合在一起 我们将要在我们的日志系统中使用topic交换器,首先假设日志的路由键有两个单词组成:<facility>.<severity>。 代码与上一篇 教程 中的代码几乎相同。 EmitLogTopic.cs的代码: using System; using System.Linq; using RabbitMQ.Client; using System.Text; class EmitLogTopic { public static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using(var connection = factory.CreateConnection()) using(var channel = connection.CreateModel()) { channel.ExchangeDeclare(exchange: "topic_logs", type: "topic"); var routingKey = (args.Length > 0) ? args[0] : "anonymous.info"; var message = (args.Length > 1) ? string.Join(" ", args.Skip(1).ToArray()) : "Hello World!"; var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "topic_logs", routingKey: routingKey, basicProperties: null, body: body); Console.WriteLine(" [x] Sent '{0}':'{1}'", routingKey, message); } } } ReceiveLogsTopic.cs的代码: using System; using RabbitMQ.Client; using RabbitMQ.Client.Events; using System.Text; class ReceiveLogsTopic { public static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using(var connection = factory.CreateConnection()) using(var channel = connection.CreateModel()) { channel.ExchangeDeclare(exchange: "topic_logs", type: "topic"); var queueName = channel.QueueDeclare().QueueName; if(args.Length < 1) { Console.Error.WriteLine("Usage: {0} [binding_key...]", Environment.GetCommandLineArgs()[0]); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); Environment.ExitCode = 1; return; } foreach(var bindingKey in args) { channel.QueueBind(queue: queueName, exchange: "topic_logs", routingKey: bindingKey); } Console.WriteLine(" [*] Waiting for messages. To exit press CTRL+C"); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); var routingKey = ea.RoutingKey; Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message); }; channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } 请运行以下示例: 要接收所有日志: cd ReceiveLogsTopic dotnet run "#" 要接收来自设备kern的所有日志: cd ReceiveLogsTopic dotnet run "kern.*" 或者,如果您只想监听级别为critical的日志: cd ReceiveLogsTopic dotnet run "*.critical" 您可以创建多个绑定: cd ReceiveLogsTopic dotnet run "kern.*" "*.critical" 使用路由键kern.critical发出日志: cd EmitLogTopic dotnet run "kern.critical" "A critical kernel error" 希望运行这些程序能让您玩得开心。要注意的是,这些代码没有针对路由键和绑定键做任何预设,您可以尝试使用两个以上的路由键参数。 ( EmitLogTopic.cs 和 ReceiveLogsTopic.cs 的完整源码) 接下来,在 教程[6] 中将了解如何将往返消息作为远程过程调用。 写在最后 本文翻译自RabbitMQ官方教程C#版本。如本文介绍内容与官方有所出入,请以官方最新内容为准。水平有限,翻译的不好请见谅,如有翻译错误还请指正。 原文链接:RabbitMQ tutorial - Topics 实验环境:RabbitMQ 3.7.4 、.NET Core 2.1.3、Visual Studio Code 最后更新:2018-09-06

优秀的个人博客,低调大师

[译]RabbitMQ教程C#版 - 路由

先决条件 本教程假定RabbitMQ已经安装,并运行在localhost标准端口(5672)。如果你使用不同的主机、端口或证书,则需要调整连接设置。 从哪里获得帮助 如果您在阅读本教程时遇到困难,可以通过邮件列表 联系我们。 路由 (使用.NET客户端) 在 教程[3] 中,我们构建了一个简单的日志系统,可以向多个接收者广播消息。 在本教程中,我们会为日志系统再添加一个特性,使其可以只订阅消息的一个子集。例如,将所有日志消息打印到 控制台,同时只会将严重错误消息写入日志文件(保存到磁盘空间)。 绑定 在前面的例子中,我们创建过绑定。不知道您是否还记得下面的代码: channel.QueueBind(queue: queueName, exchange: "logs", routingKey: ""); 绑定是指交换器和队列之间的关联关系。可以简单地理解为:某个队列对来自此交换器的消息感兴趣。 绑定可以采用额外的routingKey参数,为了避免与BasicPublish方法中相同参数混淆,我们将其称为binding key(这里是指路由键从声明角度的一种别称,绑定键)。下面即是如何使用绑定键 建立一个绑定: channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: "black"); 绑定键的含义取决于交换器类型。像我们前面使用的fanout交换器,忽略了它的值(依据fanout交换器的特性,它会把消息广播到所有订阅的队列,所以就算指定routingKey也不会根据其过滤消息)。 Direct交换器 在上篇教程中,我们的日志系统会把所有消息广播给所有消费者,现在我们想要扩展使其可以根据消息的严重性过滤消息。例如,我们希望将日志消息写入磁盘的脚本仅接收严重错误的消息,而不是在警告或者信息类型的消息上浪费磁盘空间。 之前我们使用的是fanout交换器,它没有给我们足够的灵活性 - 它只能进行无意识的广播。 现在我们要用direct交换器替换它,direct交换器背后的路由算法很简单 - 消息会进入其binding key恰好与routing key相匹配的队列。 为了说明这一点,请参考以下设置: 在上面的设置中,我们可以看到direct交换器X与两个队列绑定。第一个队列通过键orange绑定,第二个队列有两个绑定,一个通过键black绑定、另外一个通过键green绑定。 如此设置,发布使用路由键orange的消息到交换器最终会被路由到队列Q1,路由键为black或green的消息会去向队列Q2,而其他所有的消息会被丢弃。 多重绑定 使用相同的绑定键绑定多个队列是完全合法的。在示例中,我们可以在X和Q1之间添加一个键为black的绑定。这种情况下,direct交换器会像fanout交换器一样,把消息广播到所有匹配的队列,路由键为black的消息会被分别发送到队列Q1和Q2。 发送日志 我们将在日志系统中使用上述消息模型,在发送消息时使用direct交换机来替换fanout交换器。同时我们会把日志的严重性作为路由键,这样的话,接收脚本就可以选择性地接收它期望严重性的消息。首先我们来关注如何发送日志。 同样地,我们需要先创建一个交换器: channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct); 准备好发送消息: var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "direct_logs", routingKey: severity, basicProperties: null, body: body); 简单起见,我们先假定severity可以是info、warning或error任意一值。 订阅 马上就可以像前面的教程接收消息了,但有一点不同, 我们需要为我们感兴趣的每种日志严重性级别的消息建立一个新的绑定。 var queueName = channel.QueueDeclare().QueueName; foreach(var severity in args) { channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: severity); } 组合在一起 EmitLogDirect.cs类的代码: using System; using System.Linq; using RabbitMQ.Client; using System.Text; class EmitLogDirect { public static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using(var connection = factory.CreateConnection()) using(var channel = connection.CreateModel()) { channel.ExchangeDeclare(exchange: "direct_logs", type: "direct"); var severity = (args.Length > 0) ? args[0] : "info"; var message = (args.Length > 1) ? string.Join(" ", args.Skip(1).ToArray()) : "Hello World!"; var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "direct_logs", routingKey: severity, basicProperties: null, body: body); Console.WriteLine(" [x] Sent '{0}':'{1}'", severity, message); } Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } ReceiveLogsDirect.cs类的代码: using System; using RabbitMQ.Client; using RabbitMQ.Client.Events; using System.Text; class ReceiveLogsDirect { public static void Main(string[] args) { var factory = new ConnectionFactory() { HostName = "localhost" }; using(var connection = factory.CreateConnection()) using(var channel = connection.CreateModel()) { channel.ExchangeDeclare(exchange: "direct_logs", type: "direct"); var queueName = channel.QueueDeclare().QueueName; if(args.Length < 1) { Console.Error.WriteLine("Usage: {0} [info] [warning] [error]", Environment.GetCommandLineArgs()[0]); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); Environment.ExitCode = 1; return; } foreach(var severity in args) { channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: severity); } Console.WriteLine(" [*] Waiting for messages."); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); var routingKey = ea.RoutingKey; Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message); }; channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } 请像往常一样创建项目(请参阅 教程[1])。 如果您想将warning和error(不包括info)日志消息保存到文件,只需打开控制台并输入: cd ReceiveLogsDirect dotnet run warning error > logs_from_rabbit.log 如果您想在屏幕上看到所有日志消息,请打开一个新终端并执行以下操作: cd ReceiveLogsDirect dotnet run info warning error # => [*] Waiting for logs. To exit press CTRL+C 例如,想要发出error日志消息,只需要输入: cd EmitLogDirect dotnet run error "Run. Run. Or it will explode." # => [x] Sent 'error':'Run. Run. Or it will explode.' EmitLogDirect.cs 和 ReceiveLogsDirect.cs 的完整源代码。 跳转到 教程[5],了解如何基于模式监听消息。 写在最后 本文翻译自RabbitMQ官方教程C#版本。如本文介绍内容与官方有所出入,请以官方最新内容为准。水平有限,翻译的不好请见谅,如有翻译错误还请指正。 原文链接:RabbitMQ tutorial - Routing 实验环境:RabbitMQ 3.7.4 、.NET Core 2.1.3、Visual Studio Code 最后更新:2018-08-31

优秀的个人博客,低调大师

[剑指offer] JAVA版题解(全)

序号 题解 牛客 OJ 数据结构类型 03 [剑指offer] 二维数组中的查找 二维数组中的查找 数组 04 [剑指offer] 替换空格 替换空格 字符串 05 [剑指offer] 从尾到头打印链表 从尾到头打印链表 链表 06 [剑指offer] 重建二叉树 重建二叉树 树 07 [剑指offer] 用两个栈实现队列 用两个栈实现队列 栈、队列 08 [剑指offer] 旋转数组的最小数字 旋转数组的最小数字 数组 09 [剑指offer] 斐波那契数列 斐波那契数列 数组 10 [剑指offer] 二进制中1的个数 二进制中1的个数 数组 11 [剑指offer] 数值的整数次方 数值的整数次方 数值 14 [剑指offer] 调整数组顺序使奇数位于偶数前面 调整数组顺序使奇数位于偶数前面 数组 15 [剑指offer] 链表中倒数第k个结点 链表中倒数第k个结点 链表 16 [剑指offer] 反转链表 反转链表 链表 17 [剑指offer] 合并两个排序的链表 合并两个排序的链表 链表 18 [剑指offer] 树的子结构 树的子结构 树 19 [剑指offer] 二叉树的镜像 二叉树的镜像 树 20 [剑指offer] 顺时针打印矩阵 顺时针打印矩阵 数组 21 [剑指offer] 包含min函数的栈 包含min函数的栈 栈 22 [剑指offer] 栈的压入、弹出序列 栈的压入、弹出序列 栈 23 [剑指offer] 从上往下打印二叉树 从上往下打印二叉树 树 24 [剑指offer] 二叉搜索树的后序遍历序列 二叉搜索树的后序遍历序列 树 25 [剑指offer] 二叉树中和为某一值的路径 二叉树中和为某一值的路径 树 26 [剑指offer] 复杂链表的复制 复杂链表的复制 链表 27 [剑指offer] 二叉搜索树与双向链表 二叉搜索树与双向链表 树、链表 28 [剑指offer] 字符串的排列 字符串的排列 字符串 29 [剑指offer] 数组中出现次数超过一半的数字 数组中出现次数超过一半的数字 数组 30 [剑指offer] 最小的K个数 最小的k个数 数组 31 [剑指offer] 连续子数组的最大和 连续子数组的最大和 数组 32 [剑指offer] 整数中1出现的次数(从1到n整数中1出现的次数) 从1到n整数中1出现的次数 数组 33 [剑指offer] 把数组排成最小的数 把数组排成最小的数 数组 34 [剑指offer] 丑数 丑数 数值 35 [剑指offer] 第一个只出现一次的字符 第一个只出现一次的字符 字符串 36 [剑指offer] 数组中的逆序对 数组中的逆序对 数组 37 [剑指offer] 两个链表的第一个公共结点 两个链表的第一个公共结点 链表 38 [剑指offer] 数字在排序数组中出现的次数 数字在排序数组中出现的次数 数组 39 [剑指offer] 二叉树的深度 二叉树的深度 树 40 [剑指offer] 数组中只出现一次的数字 数组中只出现一次的数字 数组 41 [剑指offer] 和为S的两个数字 VS [剑指offer] 和为S的连续正数序列 和为s的两个数字 VS 和为S的连续正数序列 数值 42 [剑指offer] 翻转单词顺序列 VS [剑指offer] 左旋转字符串 翻转单词顺序 VS 左旋转字符串 字符串 44 [剑指offer] 扑克牌顺子 扑克牌的顺子 数组 45 [剑指offer] 孩子们的游戏(圆圈中最后剩下的数) 圆圈中最后剩下的数字 数组 46 [剑指offer] 求1+2+3+…+n 求1+2+…+n 233 数值 47 [剑指offer] 不用加减乘除做加法 不用加减乘除做加法 数值 49 [剑指offer] 把字符串转换成整数 把字符串转换成整数 字符串 51 [剑指offer] 数组中重复的数字 数组中重复的数字 数组 52 [剑指offer] 构建乘积数组 构建乘积数组 数组 53 [剑指offer] 正则表达式匹配 正则表达式匹配 字符串 54 [剑指offer] 表示数值的字符串 表示数值的字符串 字符串 55 [剑指offer] 字符流中第一个不重复的字符 字符流中第一个不重复的字符 字符串 56 [剑指offer] 链表中环的入口结点 链表中环的入口结点 链表 57 [剑指offer] 删除链表中重复的结点 删除链表中重复的结点 链表 58 [剑指offer] 二叉树的下一个结点 二叉树的下一个结点 树 59 [剑指offer] 对称的二叉树 对称的二叉树 树 60 [剑指offer] 按之字形顺序打印二叉树 按之字形顺序打印二叉树 树 61 [剑指offer] 把二叉树打印成多行 把二叉树打印成多行 树 62 [剑指offer] 序列化二叉树 序列化二叉树 树 63 [剑指offer] 二叉搜索树的第k个结点 二叉搜索树的第k个结点 树 64 [剑指offer] 数据流中的中位数 数据流中的中位数 数值 65 [剑指offer] 滑动窗口的最大值 滑动窗口的最大值 数组 66 [剑指offer] 矩阵中的路径 矩阵中的路径 数组 67 [剑指offer] 机器人的运动范围 机器人的运动范围 数组 Array 数组题目汇总[18题] [剑指offer] 二维数组中的查找 [剑指offer] 旋转数组的最小数字 [剑指offer] 调整数组顺序使奇数位于偶数前面 [剑指offer] 顺时针打印矩阵 [剑指offer] 数组中出现次数超过一半的数字 [剑指offer] 最小的K个数 [剑指offer] 连续子数组的最大和 [剑指offer] 把数组排成最小的数 [剑指offer] 数组中的逆序对 [剑指offer] 数字在排序数组中出现的次数 [剑指offer] 数组中只出现一次的数字 [剑指offer] 扑克牌顺子 [剑指offer] 孩子们的游戏(圆圈中最后剩下的数) [剑指offer] 数组中重复的数字 [剑指offer] 构建乘积数组 [剑指offer] 滑动窗口的最大值 [剑指offer] 矩阵中的路径 [剑指offer] 机器人的运动范围 链表题目汇总[8题] [剑指offer] 从尾到头打印链表 [剑指offer] 反转链表 [剑指offer] 链表中倒数第k个结点 [剑指offer] 合并两个排序的链表 [剑指offer] 复杂链表的复制 [剑指offer] 删除链表中重复的结点 [剑指offer] 链表中环的入口结点 [剑指offer] 两个链表的第一个公共结点 更多关于链表面试题的总结,请移步[算法总结] 一文搞懂面试链表题 二叉树题目汇总[13题] [剑指offer] 重建二叉树 [剑指offer] 树的子结构 [剑指offer] 二叉树的镜像 [剑指offer] 从上往下打印二叉树 [剑指offer] 二叉搜索树的后序遍历序列 [剑指offer] 二叉树中和为某一值的路径 [剑指offer] 二叉树的深度 [剑指offer] 二叉树的下一个结点 [剑指offer] 对称的二叉树 [剑指offer] 按之字形顺序打印二叉树 [剑指offer] 把二叉树打印成多行 [剑指offer] 序列化二叉树 [剑指offer] 二叉搜索树的第k个结点 更多关于二叉树面试题的总结,请移步 [算法总结] 20 道题搞定 BAT 面试——二叉树 堆栈和队列题目汇总[3题] [剑指offer] 用两个栈实现队列 [剑指offer] 包含min函数的栈 [剑指offer] 栈的压入、弹出序列 更多关于堆栈和队列面试题的总结,请移步 [算法总结] 6 道题搞定 BAT 面试——堆栈和队列

优秀的个人博客,低调大师

云HBase支持单节点基础版

信息摘要: HBase单节点版本是在集群版本的基础上推出的基础版本,超低成本。 适用客户: 1、开发测试场景:企业或个人开发的测试环境搭建,灵活且低门槛的HBase单节点实例能高效满足测试场景下的HBase实际需求 2、学习培训场景:个人开发者或培训机构以较低的价格获取HBase单节点实例,对其进行各类场景的测试和学习 3、非核心业务:用于线上如系统、服务器日志等可用性要求较低的业务场景,通过较低的价格创建HBase单节点实例,保障业务顺利运行的同时,降低企业的投入和管理成本 版本/规格功能: 支持单节点规格,新增基础版本产品形态。支持3种规格:1Core2G/2Core4G/4Core8G,单节点数据存放在云盘上,利用云盘的副本保证数据持久性。售价集群版本1/4不到,价格最低最低99块/3个月。 产品文档: https://help.

优秀的个人博客,低调大师

以太坊开发环境搭建linux版

本文介绍在ubuntu下如何搭建以太坊DApp的开发环境,包括nodejs、truffle、solc、web3js、ganache等。 一、安装前的准备 1.1 查看当前CPU架构 在终端中执行以下命令,确定是32位架构还是64位架构: ~$ uname –p x86_64 如果你看到输出x86_64,那么就是64位系统,否则是32位。 1.2下载工具 确保你安装了下载工具wget: ~$ wget –V GNU Wget 1.17.1 built on linux-gnu 如果还没有安装wget,使用apt-get来安装 ~$ sudo apt-get install wget 二、安装DApp开发环境 2.1 安装Node.js 首先根据你的linux是32位还是64位,分别下载不同的预编译版本,我们使用官方长期支持的8.10.0LTS版本: 64位: ~$ wget https://nodejs.org/dist/v8.10.0/node-v8.10.0-linux-x64.tar.gz 32位: ~$ wget https://nodejs.org/dist/v8.10.0/node-v8.10.0-linux-x86.tar.gz 然后解压到当前目录,以64位为例: ~$ tar zxvf node-v8.10.0-linux-x64.tar.gz 然后接下来修改.bashrc来设置相关的环境变量: ~$ echo "export NODE_HOME=$HOME/node-v8.10.0-linux-x64" >> .bashrc ~$ echo "export NODE_PATH=$NODE_HOME/lib/node_modules" >> .bashrc ~$ echo "export PATH=$NODE_HOME/bin:$PATH" >> .bashrc 最后重新载入.bashrc(或者重新登陆)来使node生效: ~$ source .bashrc 现在,你可以使用node了: ~$ node –v v8.10.0 2.2 安装节点仿真器 为了快速开发和测试以太坊DApp,我们通常使用以太坊节点仿真器来模拟区块链,最流行的节点仿真器就是Ganache,之前被称为TeseRPC。 在终端执行以下命令: ~$ npm install –g ganache-cli 安装完毕后,执行命令验证安装成功: ~$ ganache-cli Ganache CLI v6.0.3 (ganache-core: 2.0.2) 要了解ganache命令行的详细用法,可以查看以太坊ganache CLI命令行参数详解 2.3 安装solidity编译器 solidity是开发以太坊智能合约的编程语言,不熟悉的话可以查看以太坊solidity开发语言简介。 ~$ npm install –g solc 安装完毕后,执行命令验证安装成功 ~$ solcjs –version 0.40.2+commit.3155dd80.Emscripten.clang 2.4安装web3 ~$ npm install –g web3@0.20.2 安装验证: ~$ node –p 'require("web3")' {[Function: Web3] providers:{…}} 2.5安装truffle框架 执行以下命令安装truffle开发框架: ~$ npm install –g truffle 验证安装: ~$ truffle version Truffle v4.1.3 (core 4.1.3) 2.6安装webpack 执行以下命令安装webpack: ~$ npm install –g webpack@3.11.0 验证安装 ~$ webpack –v 3.11.0 三、构建示例项目 3.1 新建DApp项目 执行以下命令创建项目目录并进入该目录: ~$ mkdir demo ~$ cd demo 然后用webpack模版初始化项目骨架结构: ~/demo$ truffle unbox webpack Downloading… Unpacking… Setting up… Unbox successful. Sweet! 3.2 安装项目依赖的NPM包 执行以下命令安装nmp包: ~/demo$ npm install 3.3 修改truffle配置 truffle.js中,修改port为8545,因为ganache-cli在8545端口监听: module.exports = { networks:{ development: { … port: 8545 … } } } 3.4 启动节点 执行以下命令启动节点仿真器,以便部署合约并执行交易: ~/demo$ ganache-cli 3.5 编译合约 执行以下命令编译项目合约: ~/demo$ truffle compile 3.6 部署合约: 执行以下命令来部署合约: ~/demo$ truffle migrate 3.7 启动DApp 执行以下命令来启动DApp: ~/demo$ npm run dev 在浏览器里访问http://localhost:8080即可 如果你希望从别的机器也可以访问你的DApp应用,修改一下package.json: { scripts:{ "dev": "webpack-dev-server –-host 0.0.0.0" } } 如果你希望高效的学习以太坊DApp开发,可以访问汇智网提供的最热门在线互动教程: 适合区块链新手的以太坊DApp实战入门教程 区块链+IPFS+Node.js+MongoDB+Express去中心化以太坊电商应用开发实战 其他更多内容也可以访问这个以太坊博客。

优秀的个人博客,低调大师

自己动手写区块链(Java版)

2018年开始区块链真是火啊。一夜暴富的例子一直在传说。今天我们就自己动手写一个基本的区块链。 先简单的说一下区块链是个什么(相信你早就知道了)。 区块链就是一个链表。把一堆区块串起来就是区块链。每个block有自己的数字签名(就是一串不规则看起来叼叼的字符串),同时包含有上一个block的数字签名,然后包含一些其他的data。 大体就长这样: 是不是很熟悉,链表。 好,继续。 数字签名是什么?就是hash。 而且每个block含有前一个block的hash值,而且每个block自己的hash也是由前一个的hash计算得来的。如果前一个block(数据块)的数据发生改变,那么前一个的hash值也改变了,由此就会影响到之后的数据块的所有hash值。 所以,通过计算和对比hash值这种方式我们就可以知道区块链是不是合法的,是不是已经被篡改。 什么意思呢

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册