[{"content":"In the timeline of the CesiumJS Chinese community, I wrote:\n**June 9, 2021 * QQ Group 807482793, group members reached 3000, daily UV 600+, Cesium Chinese Website Group 2: 811457177\n**November 5, 2020 * **QQ Group 807482793, group members exceeded 2000, WeChat group reached 500 members, created WeChat Group 2.\n**November 26, 2019 * ** Registered users exceeded 400, QQ Group 807482793, group members exceeded 1000, daily UV 300+\n**May 13, 2019 * **WeChat group reached 100 members within 2 hours. To join the group, please add the Cesium Chinese Website personal account:\nMay 9, 2019 * Registered users exceeded 200, QQ Group 807482793, group members exceeded 450\nDecember 20, 2018 * Registered users exceeded 100, QQ Group 807482793, group members exceeded 170\nNovember 6, 2018 * 65 registered users, QQ Group 807482793, group members exceeded 100\nOctober 10, 2018 * 51 registered users, daily UV exceeded 100 http://blog.coinidea.com/cesiumjs-1332.html\nJune 22, 2018 * Launched for testing\nJune 19, 2018 * Acquired the cesiumcn.org domain, also accessible at cesium.coinidea.com\nMay 6, 2018 * Started secondary development of CesiumJS\nApril 21, 2015 * Reviewed the C# version of WorldWind code * Implemented a simple data visualization plugin based on the C# WorldWind version\nSeptember 1, 2012 * Started working with the C++-based OSSIM source code\nApril 1, 2009 * Started getting involved in various aspects of web development, from HTML, CSS, JavaScript to JSP, ASP.NET, PHP, jQuery, LAMP, then SSH, ThinkPHP, Yii, LNMP, then SSM, Node.js, VUE\u0026hellip; As you can see, I have some experience in web development and have been intermittently exposed to many GIS-related open-source systems. With the frontend, especially Node.js, becoming increasingly mature, and browsers offering better support for HTML5 features, I believe CesiumJS will find broad application in industrial-grade scenarios and most B/S architectures. I have also started using, familiarizing myself with, and learning its related APIs.\nAs a developer, I\u0026rsquo;ve always had a certain passion — something beyond profit that is more technology-oriented. So I registered an org domain, http://cesiumcn.org, and created an open-source Web GIS community called Cesium Chinese Website. I hope everyone will support it. You can ask questions in the community or browse this blog.\n","date":"2018-06-28T07:23:08Z","permalink":"https://blog.coinidea.com/en/p/cesiumjssharing-a-chinese-community-for-learning-cesiumjs/","title":"[CesiumJS]Sharing a Chinese Community for Learning CesiumJS"},{"content":"Cesium Chinese website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\nAt Cesium, we work every day to advance 3D geospatial technology by expanding the ecosystem around 3D Tiles — the Open Geospatial Consortium (OGC) community standard we created for streaming massive heterogeneous 3D datasets. Today, we are excited to announce that users can now convert OGC CDB datasets to 3D Tiles using the CDB to 3D Tiles pipeline.\nCDB is commonly used within the U.S. government for 3D synthetic environment modeling and simulation. It defines a standardized model and structure for storing, updating, and archiving a single \u0026ldquo;versioned\u0026rdquo; virtual representation of the Earth. CDB datasets can store natural environments and man-made structures along with their attributes and relationships.\nBy converting CDB to 3D Tiles, data can be efficiently streamed across all platforms that support 3D Tiles — including ATAK and the upcoming Cesium for Unreal — as well as between online and offline devices, while preserving the precision and detail of the original CDB. The pipeline retains feature attributes, enabling runtime querying, styling, and analysis for deeper insights into the data. All versions of CDB are supported.\nTo learn more about solutions for federal and defense, drop me a line.\nA view of downtown San Diego featuring terrain, imagery, fixed building models, instanced trees, and the Coronado Bridge in the distance, loaded as 3D Tiles in CesiumJS. See the live demo.\nOriginal article: https://cesium.com/blog/2020/11/25/cdb-to-3dtiles/\nAuthor: Brady Moore\nCesium Chinese community QQ group: 807482793\nCesium Chinese website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\n","date":"2021-02-13T16:02:38Z","permalink":"https://blog.coinidea.com/en/p/converting-cdb-to-3d-tiles-with-cesium/","title":"Converting CDB to 3D Tiles with Cesium"},{"content":"Cesium Chinese website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\niTwin Services, Bentley Systems\u0026rsquo; platform for building digital twins of infrastructure, now supports loading 3D Tiles from Cesium ion.\nThe Golden Gate Bridge, tiled into 3D Tiles with Cesium ion, visualized with iModel.js — iTwin\u0026rsquo;s open-source visualization component.\nThis makes iTwin the latest platform to integrate with ion, joining a [growing number of places](https://cesium.com/integrations/) where users can combine their own 3D datasets with ion\u0026rsquo;s global layers, including Cesium OSM Buildings and Cesium World Terrain.\nCesium World Terrain is already the default base layer that engineers rely on when creating Bentley\u0026rsquo;s ContextCapture digital twins. This latest integration enables massive 3D tilesets from ion to be streamed into iTwins, so engineers can use their preferred tools, backed by ion\u0026rsquo;s high-resolution geospatial context and 3D tiling capabilities.\nYou can also follow our tutorial to learn how to build your own digital twin by creating an interactive Cesium-based building project.\nOriginal article: https://cesium.com/blog/2020/11/02/imodeljs-supports-cesium-ion-assets/\nAuthor: Sarah Chow\nComment: Intel, the U.S. federal government\u0026hellip; Cesium has been gradually transitioning from an open-source product to an enterprise-grade product.\nCesium Chinese community QQ group: 807482793\nCesium Chinese website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\n","date":"2021-02-13T16:01:40Z","permalink":"https://blog.coinidea.com/en/p/creating-digital-twins-with-cesium-ion-and-bentleys-imodel.js/","title":"Creating Digital Twins with Cesium ion and Bentley's iModel.js"},{"content":"Cesium Chinese website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\nCesium is pleased to announce a partnership with Intel Geospatial to provide professional 3D geospatial solutions for enterprise customers across industries.\nIntel Geospatial deeply understands the value of AI-powered business insights derived from 3D geospatial data. Cesium is honored to partner with Intel Geospatial to provide best-in-class 3D geospatial technology to the Intel user community.\nIntel Geospatial combines data management, visualization, analytics, and Cesium-powered 3D tiling to deliver solutions for use cases in the energy industry such as data transmission and distribution, asset management, and remote safety inspections. The platform is designed to extend the reach of geospatial insights beyond data scientists by creating solutions that are easy for anyone to use.\nIdentifying vegetation encroachment around power poles using LiDAR point clouds in the Intel Geospatial platform.\nWith the Intel Geospatial platform, customers can combine multiple datasets — including Cesium World Terrain — with all the flexibility and precision that Cesium provides.\nIntel Geospatial builds custom enterprise solutions that allow customers to incorporate all their data into a single visualization scene alongside Cesium World Terrain.\nUsing Intel Geospatial\u0026rsquo;s AI algorithms for processing and classifying datasets, along with Cesium\u0026rsquo;s GPU-accelerated analysis tools for measurement and analysis, customers can analyze individual or combined datasets to gain the insights they need — whether for remote inspection of infrastructure, visual inspection for safety purposes, or managing power lines for better resilience.\nVisit Intel Geospatial to learn more about how industry customers are leveraging geospatial technology to maximize the value of their 3D data.\nOriginal article: https://cesium.com/blog/2020/10/27/intel-using-cesium-for-geovisual-solution/\nAuthor: Patrick Cozzi\nComment: Cesium has been focused on enterprise-level solutions, which has led to slightly slower community feature development in 2020. After all, they need to generate revenue to sustain the business.\nCesium Chinese community QQ group: 807482793\nCesium Chinese website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\n","date":"2021-02-13T16:00:55Z","permalink":"https://blog.coinidea.com/en/p/cesium-partners-with-intel-geospatial-to-provide-enterprise-geospatial-solutions/","title":"Cesium Partners with Intel Geospatial to Provide Enterprise Geospatial Solutions"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nWe (Cesium) support U.S. federal government employees working from home during the pandemic by providing free access to high-resolution models from around the world through a partnership with Maxar\u0026rsquo;s Vricon.\nKabul, Afghanistan.\nWe have now added Kabul\u0026rsquo;s 3D surface model to nearly 30 areas of interest for U.S. federal government employees. These datasets have been tiled into 3D Tiles so they can be streamed at full resolution, allowing government workers to access them quickly no matter where they work.\nIf you have a valid .gov or .mil email address, follow this tutorial to access these datasets.\nIf you\u0026rsquo;re interested in learning more about how Cesium supports the U.S. federal government, let me know. I\u0026rsquo;d be happy to talk with you.\nOriginal link: https://cesium.com/blog/2020/10/13/maxar-vricon-kabul-data-in-cesium-ion/\nAuthor: Brady Moore\nComment: Cesium\u0026rsquo;s government and enterprise outreach is getting better and better.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2021-02-13T15:59:13Z","permalink":"https://blog.coinidea.com/en/p/kabul-data-available-for-government-users/","title":"Kabul Data Available for Government Users"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nRealityCapture has joined the growing list of projects that directly support Cesium ion, alongside nearly a dozen platforms including Safe FME, Blender, and 3ds Max, which have all recently added Cesium ion integration (https://cesium.com/integrations/). With its curated global datasets, secure cloud hosting, and powerful 3D tiling pipelines, ion is the hub connecting data providers and developers with users.\nThe latest version of RealityCapture (https://www.capturingreality.com/realitycapture-supports-upload-to-cesium) includes integration with Cesium ion, allowing users to share their 3D models on the web with a single click.\nIt works by uploading the model to your Cesium ion account, where it is converted into 3D Tiles. This allows users to embed photogrammetry models for visualization on the web or on mobile devices, even if they contain millions of triangles, because higher levels of detail are streamed in as you navigate the scene.\nNorwich Castle, generated by RealityCapture and visualized with Cesium. Data captured by Jasper Mink, Terradrone Europe.\nWe are thrilled about this integration because it creates an end-to-end workflow from drone photos to web-based visualization in a geospatial context. The fact that original detail is preserved makes it ideal for visualization, as users can email a link to all parties involved and be confident that the model they see is based on the highest fidelity of the captured data.\nIf you have RealityCapture files, this tutorial will guide you on how to try this feature with your own models.\nCheck out our integration guide to learn how to connect your tools with Cesium ion, providing your users with a simple way to share their large 3D models or LiDAR data, or display them in a geospatial context.\nWith Cesium, you can share photogrammetry models on the web without simplifying them: users can even see the signs on the doors of the Norwich Castle model!\nOriginal link: https://cesium.com/blog/2020/09/18/realitycapture-and-cesium-ion/\nAuthor: Omar Shehata\nComment: Various platforms are racing to add support for Cesium. 3D Tiles is a remarkable model format.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2021-02-13T15:58:21Z","permalink":"https://blog.coinidea.com/en/p/reality-capture-adds-built-in-support-for-sharing-3d-models-via-cesium-ion/","title":"Reality Capture Adds Built-in Support for Sharing 3D Models via Cesium ion"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nWhile it had its share of challenges, 2020 was still an incredible year for Cesium, and we are grateful for the progress the team achieved together. Here are some highlights from the year:\n– Established a Smart Construction digital twin partnership with market leader Komatsu Construction (https://cesium.com/blog/2020/03/10/smart-construction/).\nCesium CEO Patrick Cozzi speaking at the Las Vegas ConExpo construction equipment exposition in March.\n– Announced a partnership with Epic Games to create Cesium for Unreal (https://cesium.com/blog/2020/06/04/cesium-for-unreal-engine/).\n– Built Project Anywhere with Epic, Microsoft, and NVIDIA (https://cesium.com/blog/2020/11/30/project-anywhere/) to demonstrate cloud/GPU/simulation gaming capabilities.\n– Partnered with the Smithsonian on the Open Access initiative (https://cesium.com/blog/2020/02/28/smithsonian/).\n– Established a partnership with Intel Geospatial.\n(https://cesium.com/blog/2020/10/27/intel-using-cesium-for-geovisual-solution/)\n– Partnered with Bentley Systems for Cesium ion/iTwin integration.\n(https://cesium.com/blog/2020/11/02/imodeljs-supports-cesium-ion-assets/)\n– Delivered Cesium Stories, Cesium OSM Buildings, and CDB to 3D Tiles.\n(https://cesium.com/blog/2020/11/25/cdb-to-3dtiles/)\nCesium OSM Buildings\n– Won the PACT Tech Startup Enterprise Award, the Geospatial Startup of the Year Award from Geospatial Media \u0026amp; Communications, and the grand prize at the GEOINT Innovation Tradecraft Competition hosted by the United States Geospatial Intelligence Foundation (USGIF) and the Open Geospatial Consortium (OGC).\n(https://cesium.com/blog/2020/08/04/usgif-tradecraft-competition-winners/)\nTrophy displayed in the Cesium Demo room.\n– Added 17 outstanding employees to the team while continuing to hire and fill open positions as fast as possible.\nWearing masks and maintaining social distance during a team field trip to the New Jersey Battleship.\n– We introduced a new home for the Cesium developer community and celebrated a major CesiumJS milestone \u0026ndash; 1 million downloads. (https://cesium.com/blog/2020/05/21/one-million-cesiumjs-downloads/)\n– NORAD Tracks Santa, powered by Cesium, entertained over 20 million people worldwide for the 8th consecutive year. (https://cesium.com/blog/2020/12/10/cesium-santa-iss/)\nThank you to everyone who supported Cesium this year. Get ready for 2021! We look forward to working with you.\nCheers to 2021!\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2021-02-13T15:53:23Z","permalink":"https://blog.coinidea.com/en/p/cesium-2020-year-in-review/","title":"Cesium 2020 Year in Review"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCesium is the winner of the 2020 PACT Tech Startup Enterprise Award!\nThe award is presented annually by the Philadelphia Alliance for Capital and Technologies (PACT) to celebrate tech innovation in the Philadelphia region.\nAs a tech startup, Cesium was recognized for its innovative platform, leadership team, growth potential, and market success.\n\u0026ldquo;A rich history of innovation, a robust technology ecosystem, and a large talent pool make Philadelphia the ideal place for Cesium,\u0026rdquo; said Cesium CEO Patrick Cozzi in his acceptance speech. \u0026ldquo;During a West Coast trip for fundraising, I was told that ambitious tech entrepreneurs should move to Silicon Valley. But we have a deep belief in Philadelphia, and we are very proud and grateful to be part of this community.\u0026rdquo;\nThis year\u0026rsquo;s event was held online due to the COVID-19 pandemic. We held a small socially-distanced gathering on the rooftop terrace with team members watching online from home.\nCesium is a proud supporter of PACT, which drives entrepreneurship by connecting growth-stage companies like ours with resources such as mentoring, funding, and talent. We want to thank the organization and award sponsor Troutman Pepper, and congratulate tech startup finalists ForMotiv and ZeroEyes.\nAuthor: Andie Tursi\nOriginal link: https://cesium.com/blog/2020/09/10/cesium-enterprise-award/\nComment: Congratulations to Cesium. Their office is in Philadelphia, not Silicon Valley.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2021-02-13T15:50:25Z","permalink":"https://blog.coinidea.com/en/p/cesium-wins-2020-pact-tech-startup-enterprise-award/","title":"Cesium Wins 2020 PACT Tech Startup Enterprise Award"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nEvery day, over 100,000 commercial flights transport passengers around the world. At any given moment, you can see the real-time positions of nearly all these flights, not to mention a large number of cargo and private flights, thanks to Flightradar24, a premier flight tracking service.\nFlightradar24 provides rich data for plane enthusiasts watching the skies overhead, news media tracking air traffic incidents, and everyday people tracking friends\u0026rsquo; and family members\u0026rsquo; flights.\nFlightradar24\u0026rsquo;s 3D view is available in both browser and mobile apps and is built with CesiumJS. The application displays real-time flight positions collected from ground and satellite ADS-B transponders, radar, and more.\n3D view in Flightradar24.\nAircraft are represented by 3D models, and viewers can navigate with a cockpit view or pan and zoom from outside the aircraft to observe the flight from any angle. When an aircraft is below 500 meters, it also casts a shadow on the terrain below, calculated based on the actual position of the sun at that time.\nAn aircraft casting a shadow on approach to an airport in the 3D view.\nUsers can click on a flight to view details such as flight number, speed, destination, altitude, arrival time, and data source. Viewers can see airports and other traffic, and even toggle flight routes.\nIn addition to the selected flight, users can also see nearby aircraft.\nFlightradar24\u0026rsquo;s real-time data serves critical information to millions of users every month, and Cesium is specifically designed to support that scenario. To get started visualizing your own time-dynamic data with Cesium, follow our simple tutorial to create a drone flight in Cesium Stories.\nOriginal link: https://cesium.com/blog/2020/08/13/flightradar24/\nAuthor: Sarah Chow\nComment: CesiumJS applications are becoming increasingly widespread.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-09-05T15:24:34Z","permalink":"https://blog.coinidea.com/en/p/tracking-world-commercial-airlines-with-flightradar24s-cesiumjs-app/","title":"Tracking World Commercial Airlines with Flightradar24's CesiumJS App"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCesium makes it easier for first responders and military operators to quickly assess and understand dense and evolving urban environments.\nCesium supports visualization at any scale, from global down to sub-centimeter. We recently improved support for underground visualization, allowing exploration of underground environments to be seamlessly integrated with above-ground data.\nRecently, we put these capabilities to the test in the Dense Urban Online Challenge, organized by the Department of Defense\u0026rsquo;s National Security Innovation Network (NSIN), aimed at addressing problems faced by first responders and military operators working in high-density cities with complex underground structures.\nFor this challenge, we partnered with Kaarta to demonstrate how Cesium can power numerous applications to solve these operational problems by bringing all data together and visualizing it, providing decision-makers with the information and insights they need.\nA section of New York City\u0026rsquo;s East Side Access tunnel, captured by Kaarta.\nAt the hackathon, we demonstrated New York City tunnels collected by Kaarta\u0026rsquo;s mobile 3D scanners. These point clouds were captured with their handheld device, simply by walking through the tunnel, with laser precision within 3 centimeters. The generated point cloud was tiled and geolocated using Cesium ion.\nThe value here is that these precise 3D scans can be captured quickly and frequently, so you can have a map that\u0026rsquo;s always up to date, even for projects under active development, like the East Side Access transit tunnel in New York City. For first responders and military operators, up-to-date maps of these dense environments are critical for decision-making.\nSince devices like these make near real-time high-resolution scanning possible, with Cesium you can combine these scans to see how all projects in any given area are developing simultaneously. By combining with other datasets, it\u0026rsquo;s easy to plan for potential conflicts \u0026ndash; for example, by overlaying maps of the sewer system to ensure it doesn\u0026rsquo;t get too close. With Cesium\u0026rsquo;s measurement tools, these analyses are simple and comprehensive.\nTop: Ground-level view of New York City with tunnel locations marked in red. Bottom: Interior view of the tunnel.\nOut of 31 teams that participated in the NSIN Dense Urban Online Challenge, we were one of 5 teams selected for the in-person hackathon. We\u0026rsquo;re excited to provide a platform that enables others to solve these complex challenges. If you\u0026rsquo;re doing underground work, or if you\u0026rsquo;re interested in Cesium for defense, please contact brady@cesium.com.\nOriginal link: https://cesium.com/blog/2020/08/25/national-security-hackathon/\nAuthor: Brady Moore\nComment: Quite impressive.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-09-05T15:21:33Z","permalink":"https://blog.coinidea.com/en/p/cesium-and-kaarta-visualize-indoor-and-underground-environments-with-high-resolution-lidar/","title":"Cesium and Kaarta Visualize Indoor and Underground Environments with High-Resolution LiDAR"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nOne of the topics from friends of the Cesium Chinese Website is: independently developing a map (tile) download tool.\nThis topic will be presented in multiple installments as blog posts [for all users] + videos [for paid users]. The source code will be continuously committed and updated. GitHub address: https://github.com/hujiulin/MapDownloader. The source code is open to all users. If you find it helpful, please give it a star for encouragement.\nThe mightiest sword has no edge; the greatest skill appears effortless.\nThe tool will ultimately be presented in C# and JavaScript. Programming languages are just the form \u0026ndash; understanding the internal logic and workflow allows you to implement it in Java, Python, PHP, or any other language.\nThe currently open-sourced tool is very simple (bare-bones), but I will regularly update and maintain the code. If you have any questions, you can submit issues on GitHub, or leave messages and ask questions on the WeChat Official Account: Cesium Chinese Website; QQ Group: 807482793; Forum: http://cesium.coinidea.com/.\nPrerequisites Find a programming language you\u0026rsquo;re familiar with that supports:\nFile download over the network. File I/O, reading and writing local folders and files. Multithreading. Desktop windows, preferably with a browser control. Generally speaking, modern programming languages support most of the above features. This article uses C#. In the middle part of this series, JavaScript will be introduced.\nTile Map Server This article uses Baidu Maps. Most tile map servers have x, y, z (level) parameters. The Baidu Maps URL pattern is: http://online{0}.map.bdimg.com/onlinelabel/?qt=tile\u0026amp;x={1}\u0026amp;y={2}\u0026amp;z={3}\u0026amp;styles=pl\u0026amp;udt=20200727\u0026amp;scaler=1\u0026amp;p=0\nIf we set x=1, y=1, z=3, and open the URL in a browser:\nhttp://online0.map.bdimg.com/onlinelabel/?qt=tile\u0026x=1\u0026y=1\u0026z=3\u0026styles=pl\u0026udt=20200727\u0026scaler=1\u0026p=0\nSample tile\nTile Download Now that we know the tile generation rules, we just need to specify the download URL to download the corresponding image. The core download code in C# is straightforward and can be easily found online:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private static WebClient wc = null; private static void initWebClientInstance() { if (null == wc) { wc = new System.Net.WebClient(); } } private static void download(string url, string filename) { // Check filename exist or not if (File.Exists(filename)) { return; } // Create directory string dir = Path.GetDirectoryName(filename); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } initWebClientInstance(); wc.DownloadFile(url, filename); } Batch Tile Download Next, we need to:\nGenerate download URLs in bulk. Download each tile in a loop. As mentioned earlier, the core concept of maps is a quadtree, so we can simply assume that the tile map is also composed of a quadtree, with approximately 18 levels (verifiable online). Thus:\nlevel minX~maxX minY~maxY 1 1~1 1~1 2 1~2 1~2 3 1~4 1~4 \u0026hellip; n 1~2^(n-1) 1~2^(n-1) Quadtree\nThe core batch download code is as follows:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void downloadBatch(string urlPattern, string targetFoler, int level) { int maxX = (int)Math.Pow(2, level - 1); int maxY = (int)Math.Pow(2, level - 1); for (int x = 0; x \u0026lt;= maxX; x++) { for (int y = 0; y \u0026lt;= maxY; y++) { string url = String.Format(urlPattern, 1, x, y, level); string filename = Path.Combine(targetFoler, level.ToString(), x.ToString()) + \u0026#34;\\\\\u0026#34; + y.ToString() + \u0026#34;.png\u0026#34;; download(url, filename); } } } The above code will work for downloading, but there are many issues. These will be discussed in the next installment.\nCurrent software interface\nDownload results\nNext Steps The current code only works for small zoom levels. At higher levels, the number of images to download becomes enormous. Multithreading, or even multiple machines, will be needed. Many of the downloaded images are pure black, which suggests our generation rules need improvement. The browser control and the software are not yet linked \u0026ndash; you can\u0026rsquo;t select a region in real-time for downloading. Later, image stitching may be needed. When loading into specific platforms, coordinate system transformations may be required. Automatic control of download intervals, dynamic IP switching. These issues will be discussed in subsequent articles.\nDisclaimer Generally speaking, map servers require significant storage and bandwidth resources. This article discusses the internal principles of current download tools from an academic perspective only. Corrections are welcome.\nAgain: GitHub address: https://github.com/hujiulin/MapDownloader. The source code is open to all users. If you find it helpful, please give it a star for encouragement.\nThis article and the software are for academic exchange only. Commercial use is strictly prohibited.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-07-27T00:43:49Z","permalink":"https://blog.coinidea.com/en/p/cesium-chinese-website--how-to-develop-a-map-download-tool-part-1/","title":"Cesium Chinese Website -- How to Develop a Map Download Tool [Part 1]"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCamptocamp has added underground visualization capabilities to swisstopo\u0026rsquo;s digital twin.\nFree Public Access to Switzerland\u0026rsquo;s 3D Map Based on 3D Tiles, the Swiss Federal Geoportal 3D Viewer provides free access to an interactive nationwide map, including terrain, bridges, buildings, and even trees \u0026ndash; over 70 million objects.\nCamptocamp has implemented these new features in swissgeol, swisstopo\u0026rsquo;s web-based 3D geological data viewer. The swisstopo 3D portal is an interactive map of Switzerland, including both natural and built environments.\nWhile this 3D map is impressive, it didn\u0026rsquo;t provide a complete picture of the country: groundwater, mineral layers, basements, parking garages, subways, and other underground parts of buildings were all missing.\nLooking Underground The Swiss Federal Office of Topography wanted to show not only what\u0026rsquo;s above ground in Switzerland, but also what\u0026rsquo;s below. Therefore, in collaboration with Camptocamp, we added support for underground visualization in CesiumJS 1.70.\nSwissgeol brings together a wealth of underground datasets, including boreholes, seismic data, and bedrock maps. These data were previously separate and two-dimensional, but by combining them, swissgeol gives users a more complete view of the subsurface.\nUnderground boreholes in swissgeol, along with buildings, terrain, and imagery data on the surface.\nAll this data streams smoothly to the browser thanks to 3D Tiles and Cesium ion\u0026rsquo;s 3D pipelines. Camptocamp uses FME, geological 3D modeling packages, and Python to preprocess the data.\nUsers can adjust the transparency of each layer, including the surface imagery, and can also view cross-sections.\nCross-section data with transparent terrain and surface imagery in swissgeol.\nGeological Data at Work The viewer is freely available to the public and will serve many needs in the geological field. Geological engineers will be able to analyze potential projects such as transport tunnels and perform risk analysis for events like rock slides. Decision-makers will have better base data for education or for selecting suitable project sites.\nFor example, although approximately 75% of Switzerland\u0026rsquo;s energy currently comes from imported fossil fuels, their new energy policy \u0026ldquo;Energy Strategy 2050\u0026rdquo; aims to increase reliance on local shallow geothermal energy.\nGeothermal datasets visualized in swissgeol.\nUntil now, creating a geothermal project proposal required gathering all the different datasets, such as geological maps, boreholes, cross-sections, 3D models, seismic data, and more. Each dataset had to be copied and stored separately, or database connections had to be established using GIS or 3D modeling software. Datasets could only be visualized in 2D or in model-based 3D. Swissgeol greatly simplifies this process by bringing all datasets together in a single portal that can be shared instantly.\nVisualization of deep geothermal wells with complex fault patterns and seismic locations.\nFuture Outlook Swissgeol is currently in beta. In the future, swisstopo and Camptocamp plan to add features including picking and styling, so that relevant attributes of the data can be queried, filtered, analyzed, and downloaded. Registered users who need additional functionality, including swisstopo\u0026rsquo;s own users, will also be able to access other features such as uploading/downloading user-generated data and creating closed user groups to share sensitive data with a limited number of users.\nIf you have underground data, you can visualize it alongside all your other 2D and 3D data by uploading it to Cesium ion.\nAuthor: Sarah Chow\nOriginal link: https://cesium.com/blog/2020/07/06/camptocamp-underground-visualization-with-cesium/\nComment: The underground visualization based on Cesium that everyone has been hoping for is becoming increasingly mature.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-07-14T06:43:17Z","permalink":"https://blog.coinidea.com/en/p/visualizing-switzerlands-geological-resources-with-cesiums-underground-rendering/","title":"Visualizing Switzerland's Geological Resources with Cesium's Underground Rendering"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nOne key improvement introduced in this month\u0026rsquo;s CesiumJS 1.70 release is underground data visualization. This allows users to seamlessly transition from ground-level features across an entire city to underground features in the same scene, whether it\u0026rsquo;s utility data like water pipes and cables, or 3D structures like caves and mines.\nVisualizing boreholes with different ground materials by depth. Data from the University of Minnesota Borehole Geophysical Database.\nFusing underground data with 3D terrain and other layers in CesiumJS means all relevant information can be visualized in one place without constantly switching between specialized tools. For example, you can visualize earthquakes over time and measure their distance to critical city infrastructure by adding Cesium OSM Buildings to the scene.\nObserving earthquakes in the Sawtooth Mountains of central Idaho during April and May 2020. Each sphere contains metadata about the earthquake\u0026rsquo;s epicenter magnitude and depth, as well as error margins for these measurements.\nYou can control how underground data is visualized using the CesiumJS API. Below, photogrammetry of a tunnel is visualized. By keeping the ground mostly opaque, we can accurately see which parts are above ground (just the entrance) and how far the structure extends. We can also configure the camera to hide the ground when zoomed in at close range, allowing us to walk through the tunnel unobstructed.\nPhotogrammetry of old military tunnels at North Head, Auckland, New Zealand. Left: Keeping the ground mostly opaque to see which parts of the model are above ground. Right: Hiding the ground near the camera to allow users to walk inside the tunnel. Screenshots by b_nealie.\nTry It Out Upload your underground data to Cesium ion or check out the following example code to learn how to use underground features in your Cesium app.\nEnable globe transparency (https://sandcastle.cesium.com/index.html?src=Globe Translucency.html) Enable transparency only on a section of the ground (https://sandcastle.cesium.com/index.html?src=Globe Interior.html) Customize the look of underground scenes (https://sandcastle.cesium.com/index.html?src=Underground Color.html) If you have any questions or want to share your work, please visit let us know on the forum.\nYou can also visit Cesium Chinese Website: http://cesium.coinidea.com/\nAuthor: Omar Shehata\nOriginal link: https://cesium.com/blog/2020/06/16/visualizing-underground/\nComment: This is the last of the three major features in Cesium 1.70. A year or two ago, many people were asking how to make the globe transparent or what to do with underground models. Now there are solutions for these.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-06-21T06:55:52Z","permalink":"https://blog.coinidea.com/en/p/visualizing-underground-utilities-mines-and-geological-layers-with-cesium/","title":"Visualizing Underground Utilities, Mines, and Geological Layers with Cesium"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nWith the current 1.70 release, CesiumJS now ships with official TypeScript type definitions!\nTypeScript definitions have been a long-requested feature. While the community has done work supporting various manual approaches, the most popular being @types/cesium, the sheer size and evolving nature of the Cesium codebase made manual maintenance an endless task. The official definition file Cesium.d.ts is over 42,000 lines and 1.9MB in size.\nEven if you\u0026rsquo;re not a TypeScript user, this work has improved the correctness and completeness of the CesiumJS API reference documentation and enables better IntelliSense support in IDEs that can apply TypeScript definitions for type inference, making it a huge win for the entire CesiumJS community.\nUpdating CesiumJS to 1.70 will automatically leverage type checking in TypeScript applications. We use the types field in package.json, which requires no additional configuration in most cases. However, if you import individual Cesium source files directly, you\u0026rsquo;ll need to add \u0026ldquo;types\u0026rdquo;: [\u0026ldquo;cesium\u0026rdquo;] to your tsconfig.json to pick up the definitions. If you were previously using @types/cesium, you can remove it.\nOfficial support from the CesiumJS team means the latest and correct definition file will ship with every release. It also means TypeScript support will be officially tracked as part of the CesiumJS GitHub repository. If you find a bug when using CesiumJS with TypeScript, please open an issue or better yet, a pull request to fix it. If you have questions about CesiumJS/TypeScript or need help debugging your project, please ask on the community forum.\nIf you\u0026rsquo;re using custom or @types/cesium definitions and aren\u0026rsquo;t ready to switch, you can delete Source/cesium.d.ts after installation. TypeScript tooling will then fall back to the next set of CesiumJS type definitions it finds.\nThe official type definition file, Cesium.d.ts, documents over 42,000 lines of declarations and documentation, weighing in at 1.9MB.\nDeep Dive While we\u0026rsquo;re excited to finally officially support TypeScript, it took some effort to get here. Initially, we explored 3 options:\nManually Maintaining the Definition File We could manually manage and maintain our own TypeScript definition file as part of the CesiumJS codebase, most likely with a separate definition file for each JavaScript file, making it easier to manage \u0026ndash; for example, Cartesian3.js would have a corresponding Cartesian3.d.ts. This would be technically easy to implement, but would cause significant harm in terms of file synchronization and maintainability.\nAdditionally, we didn\u0026rsquo;t want to include only declaration interfaces without inline documentation, so users could take full advantage of IntelliSense. This was our last resort, but if it turned out to be the only viable option, it would be our final choice.\nPorting CesiumJS to TypeScript You may be surprised to hear that we actually evaluated rewriting all of CesiumJS in TypeScript. For TypeScript developers, this would be a huge improvement, and for CesiumJS maintainers and the codebase, it would be a real win. Beyond strong type checking, it would allow us to quickly adopt modern conventions like template literals, arrow functions, and async/await, which we currently don\u0026rsquo;t allow in the CesiumJS codebase due to compatibility and tooling reasons.\nUnfortunately, the level of effort and volume of work required made it an unattractive option in the short term. This option is still on the table, but like the large-scale ES6 migration we did last year, it would require significant careful planning, research, and infrastructure work to execute properly.\nGenerating Definition Files with the TypeScript Compiler Starting with TypeScript 3.7, the compiler can compile JavaScript code with JSDoc annotations and generate corresponding type definition files for us. This approach completely eliminates the need for manual .d.ts file maintenance and has the additional benefit of validating and improving our own JSDoc annotations, since they need to be accurate to generate correct type definitions. Needless to say, this option was very attractive to us, and we decided to pursue it after some preliminary prototyping experiments showed it could work.\nIn practice, we spent several weeks working through this approach. Marco Hutter was heavily involved in documentation fixes and source code adjustments to make the compiler happy. Early work was promising. As expected, it exposed errors and inconsistencies in JSDoc annotations and, to a lesser extent, in the CesiumJS API that we fixed. Unfortunately, we soon hit a wall.\nRelying on the TypeScript compiler meant we lacked options when it did something incorrect or unexpected. While the compiler uses JSDoc annotations in some cases, in many cases it relies on its own type inference and provides no way for us to override it. It also completely ignores much of the JSDoc, such as on object-defined properties, and exposes all private underscore variables as part of the definitions. This led us to bend the CesiumJS codebase in ways we were uncomfortable with, just to make the TypeScript compiler happy. We considered trying to modify the TypeScript compiler itself, but we would have had to dive deep into the compiler code, and we weren\u0026rsquo;t sure what the maintainers would accept or how long the process would take. Ultimately, our favorite solution became a drawn-out gamble, and we lost confidence in the approach.\nLeft: JSDoc for UrlTemplateImageryProvider that unexpectedly adds properties to BingMapsImageryProvider; Right: The generated BingMapsImageryProvider definition with duplicate definitions, causing compilation failure.\nBack to the Drawing Board As it turned out, we were so excited about TypeScript\u0026rsquo;s official JSDoc support that we completely overlooked a similar option: tsd-jsdoc. tsd-jsdoc is a JSDoc plugin that generates TypeScript definitions from JSDoc output. This makes it very similar to the TypeScript compiler approach, but provides much more flexibility over the generated type definitions.\ntsd-jsdoc doesn\u0026rsquo;t directly parse JavaScript but instead relies on the abstract syntax tree (AST) generated by JSDoc. This means it\u0026rsquo;s not affected by type inference issues or lack of JSDoc completeness that nearly derailed the TypeScript compiler approach. If we can express a type using JSDoc annotations, then it appears in the type definition file as we want it.\nWe had already learned a lot from our earlier TypeScript compiler approach failures, so we were able to complete a feasibility evaluation quite quickly, and all the issues with our existing incorrect JSDoc still applied. Things progressed faster than we expected, and we knew we had found the solution.\nAs developers, sometimes we get so focused on a particular technology that we overlook other options. In this case, community member @bampakoa had even submitted pull requests to both CesiumJS and tsd-jsdoc last year to make them more compatible. We already knew tsd-jsdoc existed, but we had overlooked it in our initial evaluation because we assumed the TypeScript compiler option would be better, and we inadvertently developed a blind spot for tsd-jsdoc.\nPost-Processing and Validation While the tsd-jsdoc output is fairly high quality out of the box, we did some additional post-processing to further improve it. This includes simple string manipulation, regex find-and-replace, and even using the TypeScript compiler to rewrite parts of the file. All of this happens as part of the new build-ts gulp task. If you\u0026rsquo;re curious, you can check out the code. The final result is a single Cesium.d.ts that serves as the entry point for the generated Cesium.js module.\nIn addition to generating the output, the build-ts task also validates the file by compiling it with TypeScript. If a developer makes a mistake in JSDoc, such as misspelling a class name or referencing a private or non-existent type, the build process will fail. While this validation process is very useful, it only catches certain types of errors. For example, if someone implements a new ImageryProvider that doesn\u0026rsquo;t conform to the correct interface, the definition file will compile without errors, but TypeScript will emit a compilation error in applications that try to use the new class as an ImageryProvider.\nWe\u0026rsquo;re still exploring ideas for adding additional validation, such as writing some unit tests in TypeScript to identify potential problem areas during development.\nJSDoc Errors I\u0026rsquo;ve mentioned several times that a particularly exciting aspect of the JSDoc-based approach is that it adds another level of inspection and validation to our documentation, benefiting everyone, not just TypeScript developers. A major part of our documentation review process is now automated. The issues we found in the codebase can be categorized as follows:\nIncorrect or incomplete types - In many cases, we used informal or incorrect names for types, for example, Image instead of HTMLImageElement, Canvas instead of HTMLCanvasElement. An interesting example is TypedArray, which doesn\u0026rsquo;t even exist at the specification level but is a common term for the full list of types like Int8Array, Float32Array, etc. We also had incomplete generics, such as Promise instead of Promise. @exports - We used JSDoc\u0026rsquo;s @exports tag as a final fallback. If a developer couldn\u0026rsquo;t get something to show up in the generated HTML, they might add @exports, which would \u0026ldquo;just work.\u0026rdquo; We used @exports for enums, namespaces, and functions instead of the @enum, @namespace, and @function tags. This led to incorrect type generation. In practice, we don\u0026rsquo;t need @exports anywhere in the code. Private type leaks - Many private types were referenced in the public API. These private types don\u0026rsquo;t exist in the HTML output and are just silent failures for our documentation build step. In most cases, it made sense to simply make the private types public. Thankfully, we also have a habit of documenting private types in CesiumJS, so we didn\u0026rsquo;t have to write new JSDoc. Copy-paste errors - The last category of JSDoc errors was duplicate parameter entries related to copy-and-paste, such as having ImageryProvider A declare that it\u0026rsquo;s documenting properties on ImageryProvider B, etc. Next Steps Once the community starts using these definitions, we expect some minor issues to surface over the next few CesiumJS releases. We\u0026rsquo;ve also started developing a list of ideas we want to explore, such as leveraging generics for the property interfaces used by the Entity API. Ultimately, we rely on the community to tell us what matters most to developers so we can shape our CesiumJS TypeScript roadmap.\nWe also want to figure out a way to use the TypeScript definitions within the CesiumJS codebase itself. We believe VSCode has some mechanisms for this, but we haven\u0026rsquo;t explored them yet. If this proves feasible, it would be a major win and would enable another level of validation through plain JavaScript, not to mention making developing CesiumJS an even better experience than it already is.\nI\u0026rsquo;m sure many people perked up when I mentioned that we evaluated rewriting CesiumJS in TypeScript. I\u0026rsquo;m absolutely in favor of this in the long run. As part of the evaluation process, I actually used the TypeScript compiler to build the existing JavaScript codebase and even ported some basic files (like Cartesian3.js) to TypeScript to understand how to do TS/JS hybrid development, rather than an \u0026ldquo;all-at-once\u0026rdquo; migration strategy. Much like ES6, porting the code is the easy part. Expect a GitHub issue soon that will break down everything that needs to happen to make a TypeScript version of CesiumJS a reality; but there are no commitments yet.\nAcknowledgements I just want to thank the community once again for helping generate ideas and discussions about TypeScript over the past few years. Special thanks to @thw0rted, who was the first external contributor to improve the initial TypeScript type definitions and provided a lot of great feedback in the original pull request. Finally, a huge thanks to my partner and co-maintainer Kevin Ring, who not only provided extensive expert knowledge and feedback but also dove into the work himself, ultimately making a series of improvements to the code.\nAuthor: Matthew Amato\nOriginal link: https://cesium.com/blog/2020/06/01/cesiumjs-tsd/\nComment: The introduction of TypeScript makes CesiumJS a more professional library and easier to maintain. Of course, the migration process is painful.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-06-13T15:37:36Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-adds-official-typescript-type-definitions/","title":"CesiumJS Adds Official TypeScript Type Definitions"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nWe are excited to announce Cesium OSM Buildings, a global 3D building layer covering the entire world, based on OpenStreetMap building data. This is the latest addition to Cesium\u0026rsquo;s global base layer suite, which includes global terrain maps, aerial imagery, and street maps already available on Cesium ion.\nNew York City, Seattle, Washington D.C., and the Burj Khalifa in Dubai shown in Cesium OSM Buildings.\nTake a tour in Cesium Stories - Take a tour in Cesium Stories\nCesium OSM Buildings is a great foundation on which to overlay high-resolution data for urban environments and more immersive experiences. Crowd-sourced and regularly updated, this base layer data will serve endless use cases: from cities that need shareable 3D solutions for urban planning, tax assessment, or traffic management, to developers who want to visualize BIM models in the real world, to government agencies that need innovative tools for training and simulation.\nCesium OSM Buildings is included in every Cesium ion subscription starting today and is included by default in any newly created Cesium layer. You can also add it to your CesiumJS application with a few lines of code:\nvar viewer = new Cesium.Viewer('cesiumContainer'); viewer.scene.primitives.add(Cesium.createOsmBuildings()); Cesium OSM Buildings consists of over 350 million buildings. While the full dataset is hundreds of gigabytes in size, it can be efficiently streamed and visualized on the web through the magic of 3D Tiles. 3D Tiles is an open standard, so Cesium OSM Buildings can be used in any compatible viewer, not just open-source Cesium.\nOpenStreetMap provides rich metadata in most cities, such as building names, addresses, and opening hours.\nCesium OSM Buildings sits solidly on Cesium World Terrain with clean edge outlines, and each building is individually selectable and stylable. In most cities, the rich metadata associated with each building, and even individual parts of buildings, can be used with dynamic styling. For example, we can highlight all commercial and residential buildings to see patterns across different neighborhoods in a city.\nHighlighting all office and commercial buildings in green using Cesium Stories.\nCesium OSM Buildings is derived from the well-known community-driven mapping project OpenStreetMap. This means anyone can improve the dataset! If you\u0026rsquo;ve ever contributed, heartfelt thanks!\nPlease try out the data and let us know what you think. We look forward to your buildings!\nAuthor: Kevin Ring Original link: https://cesium.com/blog/2020/06/01/cesium-osm-buildings/ Comment: Quite powerful, let\u0026rsquo;s get started. But it requires an internet connection.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-06-13T14:11:38Z","permalink":"https://blog.coinidea.com/en/p/cesium-1.70-introducing-cesium-osm-buildings-new-features/","title":"Cesium 1.70 - Introducing Cesium OSM Buildings New Features"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nNothing better demonstrates Cesium\u0026rsquo;s belief in combining geospatial and 3D computer graphics than the support of Epic Games and the Epic MegaGrants program to build Cesium for Unreal Engine.\nThis marks the first time a full-scale, high-precision 3D digital globe has been brought into a leading game engine, opening up a world of possibilities for Unreal users. Together, we will advance training and simulation, architecture, gaming, AR/VR, autonomous driving, and other industries by bringing 3D Tiles into the Unreal world to accurately visualize real-world locations captured by satellites and drones \u0026ndash; using the same 3D geospatial knowledge that CesiumJS has employed for nearly a decade.\nHigh-resolution photogrammetry 3D Tileset captured by drone at AGI headquarters, where Cesium was incubated.\n\u0026ldquo;Our vision is to allow the simulation community to integrate Unreal Engine into their software architecture without having to change the way they work. Defining this 3D Tiles plugin with the Cesium team is a very exciting experience because it will allow the GeoInt community to streamline their pipelines. This activity is very much in line with our vision for big open worlds for all Unreal Engine users.\u0026rdquo; \u0026ndash; Sebastien Loze, Simulation Industry Manager at Epic Games\nWhen I started graphics programming in 1994, Epic, or Epic Megames as they were known then, was an inspiration. The graphics and gameplay of the DOS games they released were light years ahead of anything I had seen.\nToday, Epic\u0026rsquo;s visual quality continues to inspire, especially with the announced Unreal Engine 5 approaching cinematic CG quality, with the Nanite virtualized micro-polygon pipeline and the Lumen dynamic global illumination engine. Combining Unreal\u0026rsquo;s strengths with Cesium\u0026rsquo;s advantages in global scale, precision, performance, and interoperability is a rare opportunity to advance 3D geospatial.\nOur focus is on growing the 3D geospatial ecosystem using the 3D Tiles format: an OGC Community Standard for efficiently streaming massive heterogeneous real-world 3D datasets for visualization and analysis.\n3D Tiles are widely used by government and commercial entities for global-scale terrain, city-wide photogrammetry, and massive point clouds from LiDAR. 3D Tiles support streaming of massive geometry and textures, as well as semantics computed by AI algorithms for runtime filtering, styling, and analysis. For example, point classification in point clouds can be used to filter foliage, or material properties on the sides of buildings in photogrammetry models can be used for communication networks, where RF propagation considers concrete or glass.\nCesium for Unreal will be open source and free on the Unreal Marketplace.\nCesium for Unreal will connect to the Cesium ion SaaS platform by default, providing ready-to-use 3D Tiles for terrain and 3D buildings, as well as first-class content pipelines for generating efficient 3D Tiles from source data such as terrain, imagery, and photogrammetry models. Cesium for Unreal will also be able to stream 3D Tiles with Cesium ion on internal private networks.\nStay tuned as we make progress. Feel free to reach out to discuss collaboration or share your Cesium for Unreal use cases.\nAuthor: Patrick Cozzi Original link: https://cesium.com/blog/2020/06/04/cesium-for-unreal-engine/ Comment: Epic, Unreal Engine \u0026ndash; gamers should all know about these. Cesium\u0026rsquo;s momentum is truly impressive.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-06-07T05:27:05Z","permalink":"https://blog.coinidea.com/en/p/announcing-partnership-with-epic-games-to-create-cesium-for-unreal-engine/","title":"Announcing Partnership with Epic Games to Create Cesium for Unreal Engine"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nOn June 1, 2020, CesiumJS released version 1.70, bringing 3 major updates.\nCesium OSM Buildings Cesium OSM Buildings is a global 3D building layer covering the entire world, built using OpenStreetMap data. It\u0026rsquo;s available as a 3D Tileset for all Cesium ion users and comes with rich feature data such as building names, addresses, opening hours, and more.\nNew York City, Seattle, Washington D.C., and the Burj Khalifa in Dubai shown in Cesium OSM Buildings.\nRead more about this new global layer and how to use it in your applications.\nUnderground Support Cesium now has better support for visualizing underground scenes, from large geological layers underground to mines, caves, and utilities. CesiumJS 1.70 adds the ability to make the globe translucent, enabling data visualization underground and allowing the camera to freely move below the surface.\nMaking the ground translucent to see underground objects. Explore this example in Sandcastle (https://sandcastle.cesium.com/index.html?src=Globe Translucency.html). This is a Parc lead mine in North Wales by Dr. Edward Allen Sherlock Hart.\nThese CesiumJS improvements are part of a collaboration with friends at Camptocamp. Their work supports the Swiss Federal Office of Topography (swisstopo), which is using Cesium to create an interactive 3D map of the country.\nCamptocamp is using these new underground features in swissgeol, a 3D web-based geological data viewer. Its goal is to visualize many different datasets in a single scene, such as boreholes, seismic data, and the ability to view ground cross-sections. Camptocamp said about this new Cesium-based viewer:\nThe 3D underground viewer swissgeol will be the main entry point for swisstopo to access geological data in the future, and it could become an essential collaboration tool for the entire earth science community in Switzerland and surrounding areas.\nVisualizing bedrock beneath the terrain in Camptocamp\u0026rsquo;s 3D underground viewer.\nThese live code examples show how to use the new globe transparency features:\nHow to enable globe transparency (https://sandcastle.cesium.com/index.html?src=Globe Translucency.html\u0026amp;label=New in 1.69) Enable transparency only on a section of the ground (https://sandcastle.cesium.com/index.html?src=Globe Interior.html) Customize what\u0026rsquo;s visible underground (https://sandcastle.cesium.com/index.html?src=Underground Color.html\u0026amp;label=New in 1.69) TypeScript Finally, in version 1.70, CesiumJS now ships with official TypeScript type definitions! The latest and correct definition file will be released with each new version, and TypeScript support will be officially tracked as part of the CesiumJS GitHub repository.\nEven if you\u0026rsquo;re not a TypeScript user, the nature of this work has improved the correctness and completeness of the CesiumJS API reference documentation, making it a big win for the entire CesiumJS community.\nRead more about how this works and the effort involved in Matt\u0026rsquo;s deep architectural dive.\nTry CesiumJS 1.70 Update to the latest CesiumJS and let us know what you think! You can post any feedback and questions about this release in this forum thread | Cesium Chinese Community: http://cesium.coinidea.com/.\nDownload link:\nAuthor: Omar Shehata\nOriginal link: https://cesium.com/blog/2020/06/01/cesium-june-release/\nComment: TypeScript makes the framework more robust and professional. Cesium OSM is indeed great, but it requires Cesium ion, showing Cesium\u0026rsquo;s determination to promote Cesium ion.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-06-07T04:40:14Z","permalink":"https://blog.coinidea.com/en/p/underground-typescript-and-global-3d-buildings-released-in-cesiumjs-1.70/","title":"Underground, TypeScript, and Global 3D Buildings Released in CesiumJS 1.70"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCesiumJS total downloads have surpassed 1 million. This milestone means a lot to us (Cesium) and the CesiumJS community.\nSince CesiumJS was released as an open-source project in April 2012, it has been downloaded over 1 million times.\n1 Million Downloads Is the Result of 200+ Contributors Working Together Since Cesium was released as an open-source project in April 2012, over 200 developers have contributed to the project. We appreciate everything the community has done, from features to bug fixes to documentation. Want to join the contributor community? Try one of the \u0026ldquo;beginner\u0026rdquo; issues.\nCesium contributors. The average number of commits among the top 10 contributors is 1,618, shown in larger size.\n1 Million Downloads Means Thousands of 3D Geospatial Applications The CesiumJS developer community has built thousands of applications with CesiumJS across dozens of industries, from drones to history to extreme sports. They\u0026rsquo;ve visualized commercial real estate spaces, major hurricanes, yacht races, and Mars rover expeditions.\n1 Million Downloads Means Millions of Lines of Code CesiumJS is one of the most comprehensive JavaScript libraries, providing an interactive 3D digital globe, star map, terrain, imagery, dynamic lighting, and an interactive timeline. Since CesiumJS development began, we\u0026rsquo;ve released updates and improvements every month, cumulatively adding over 9 million lines of code and removing over 7 million as we continue to improve the efficiency of streaming massive data online.\nMount Everest in Cesium, 2013\nMount Everest in Cesium, 2020\n1 Million Downloads Is Just the Beginning Cesium originated from the work of a few engineers at Analytical Graphics, Inc. Last year, we incorporated as our own company and spun off with an open-core business model, ensuring the long-term sustainability of CesiumJS.\nCesium developers, 2013. From left to right: Hannah Pinkos, Dan Bagnell, Patrick Cozzi, Matt Amato, and Scott Hunter.\nWorking on Cesium in February 2014. When a power outage at the office threatened development velocity, the team headed to Kevin Ring\u0026rsquo;s basement to work on Cesium using generator power. Around the table, from left to right: Greg Beatty, Scott Hunter, The Captain, Patrick Cozzi, Richard Page, Matt Amato**\nCesium Team, 2020\u0026hellip; and growing\nWe couldn\u0026rsquo;t have done it without you. Thank you for using and sharing CesiumJS, for participating in our forum, for sharing your work with us, and for the incredible applications you\u0026rsquo;ve built. We look forward to many more!\nCesium keeps getting better\nAuthor: Sarah Chow Original link: https://cesium.com/blog/2020/05/21/one-million-cesiumjs-downloads/ Comment: Cesium keeps getting better. A rising star.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-06-07T02:55:12Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-downloads-surpass-1-million/","title":"CesiumJS Downloads Surpass 1 Million"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCesium has just completed migrating their Google Groups forum to Discourse, a modern open-source platform for online communities. This is the biggest update to the Cesium community forum since its inception. The forum brings together nearly a decade of GIS-related wisdom, from basic troubleshooting to discussions about the best ways to visualize the world, with over 30,000 posts.\nMost people come to the Cesium community with real-world data they want to understand. Often this is their first foray into 3D mapping. Like many others, they learn through searching the forum why precision matters in many applications, or what happens when the curvature of the earth is not taken into account.\nIf you\u0026rsquo;ve ever asked a question on the Cesium forum, I want to thank you for contributing to this unique archive of computer graphics and geospatial knowledge!\nThe homepage of the new Cesium official English forum with new discussion categories.\nCesium has adopted Discourse to make discovering and sharing knowledge about Cesium and 3D geospatial easier. Using Discourse brings better search and formatting tools, better layout especially on mobile devices, faster page loading, and many new features.\nEverything about the new forum is customizable, so we hope it will evolve alongside our growing community. For example, we just enabled embedding Cesium Stories directly in forum posts:\nYou can now embed Cesium Stories directly in forum posts! Above is a virtual tour of Denver created for the American Association of Geographers conference.\nBrowse the forum and let us know what you think about the forum. If you\u0026rsquo;ve previously posted on the old forum, see these instructions for how to reclaim your account on the new forum.\nThe new forum not only makes it easier for users to find the answers they need, but is a collaborative space where users can share their work with the broader Cesium ecosystem. See you there!\nVisit: community.cesium.com\nAuthor: Omar Shehata\nOriginal link: https://cesium.com/blog/2020/05/04/new-community-forum/\nComment: This is the official English forum for Cesium. You can search for answers and ask questions there.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-05-17T13:48:11Z","permalink":"https://blog.coinidea.com/en/p/cesium-official-english-forum/","title":"Cesium Official English Forum"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nMunakata City in Japan\u0026rsquo;s Tottori Prefecture uses the i-Urban Renovation application built on Cesium to help residents access building data online.\nMunakata City, Japan\nLocal governments across Japan collect data about buildings, including their use, number of floors, construction materials, and year of construction. Munakata City, located in the northern part of Fukuoka Prefecture, tasked their Urban Structure Visualization Promotion Organization to make this data available to the public in an easy-to-understand format.\nDistribution of buildings in Munakata City. Building counts are aggregated into an area grid (1km grid) and displayed as a 3D mesh chart using mesh codes shown in Cesium. Since the grid is linked to location information and building counts, it\u0026rsquo;s a convenient demonstration tool when explaining local characteristics to residents.\nThe i-Urban Renovation app is built on CesiumJS for visualizing and sharing data. Even though Munakata City covers approximately 120 square kilometers filled with various buildings, the app efficiently streams building data using 3D Tiles.\nClassifying buildings by use and comparing land use requirements. Users can also achieve similar functionality using Cesium Stories, which supports 3D Tiles styling.\nUsing the Cesium app, users can see the current status of any building. Buildings can be color-coded based on various metrics, including:\nUse, such as residential, commercial, government, agricultural, etc. Number of floors, making it easy to distinguish the distribution of high-rise and low-rise buildings. Construction materials, such as wood or reinforced concrete. Year of construction, showing the distribution of new and old buildings. Additionally, users can examine the relationship between building use and land use regulations by combining the building dataset with the land use zoning dataset. When a user clicks on a building, detailed building attributes are displayed.\nViewing building usage. Click on individual buildings to see detailed data. We recently added feature picking to Cesium Stories to build your own solutions using Cesium Stories.\nVisit i-Urban Renovation or the data encoding specification, or upload your own data to Cesium ion to easily generate your own Cesium Stream 3D Tiles.\nAuthor: Sarah Chow\nOriginal link: https://cesium.com/blog/2020/03/31/i-urban-renovation-visualizes-munakata/\nComment: Although this is still encouraging everyone to use Cesium ion, we can see that Cesium performs well in large-scale scenarios.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-04-23T08:00:16Z","permalink":"https://blog.coinidea.com/en/p/i-urban-renovation-visualizes-building-status-in-munakata-tottori-prefecture-using-3d-tiles/","title":"i-Urban Renovation Visualizes Building Status in Munakata, Tottori Prefecture Using 3D Tiles"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nPelican Mapping is excited to announce support for loading 3D Tiles and Bing imagery from Cesium ion into their osgEarth digital earth rendering toolkit.\nAdding 3D Tiles Support osgEarth rendering data from Cesium ion for Melbourne, Australia\nOver the past year, we\u0026rsquo;ve been developing support for 3D Tiles in osgEarth, and it has proven to be an exciting and efficient runtime format. We first developed a glTF reader/writer for OpenSceneGraph based on TinyGLTF. Building on top of that, we built a 3D Tiles Layer plugin for osgEarth to handle streaming tiles. osgEarth uses the same screen space error metric that Cesium uses to decide when to load and display tiles, so the 3D Tiles layer should look the same in osgEarth as it does in Cesium. After developing the 3D Tiles loader, we were able to quickly add support for Cesium ion by adding authorization-based ion tokens to the 3D Tiles layer.\nBing Maps osgEarth rendering Bing imagery with labels via Cesium ion\nWe also added support for Bing Maps from Cesium ion to osgEarth. osgEarth already had a Bing imagery driver, so we used Cesium ion\u0026rsquo;s API to get the Bing key and map style, and then created an osgEarth Bing imagery layer on top of the driver, with credentials provided by Cesium ion. We hope to add support for more external imagery types in the future.\nPutting It All Together Here is an example Earth file showing how to load content from Cesium ion into osgEarth.\n\u0026lt;map name=\"Cesium ion\"\u0026gt; \u0026lt;CesiumIonImage name=\"Bing Maps Aerial With Labels\"\u0026gt; \u0026lt;asset_id\u0026gt;3\u0026lt;/asset_id\u0026gt; \u0026lt;/CesiumIonImage\u0026gt; \u0026lt;CesiumIon3DTiles name=\"Melbourne\"\u0026gt; \u0026lt;asset_id\u0026gt;69380\u0026lt;/asset_id\u0026gt; \u0026lt;/CesiumIon3DTiles\u0026gt; \u0026lt;/map\u0026gt; You can set the Cesium ion token as an environment variable, then load the earth file using any osgEarth-based application.\nexport OSGEARTH_CESIUMION_KEY=YOUR_API_KEY osgearth_viewer cesiumion.earth Author: Jason Beverage\nOriginal link: https://cesium.com/blog/2020/04/02/osgearth-supports-cesium-ion-assets/\nComment: osgEarth announces support for Cesium ion.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-04-19T14:44:51Z","permalink":"https://blog.coinidea.com/en/p/bringing-3d-tiles-and-bing-imagery-from-cesium-ion-to-osgearth/","title":"Bringing 3D Tiles and Bing Imagery from Cesium ion to osgEarth"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nMany Cesium users frequently need to visualize hundreds of thousands of 3D buildings across entire cities for real estate, urban planning, or civil engineering projects. To make it easier to create useful digital twins for these industries, we just added support for embedding feature data when uploading KML/COLLADA to Cesium ion.\nThis means you can now export your 3D buildings from modeling tools (such as CityEngine, Rhino, and 3DCityDB) and include per-building attributes when sharing data on the Cesium ion web.\nPhiladelphia 3D buildings combined with Cesium World Terrain. Each building can be clicked to display its name, address, and parcel number.\nCesium ion converts your buildings into 3D Tiles to optimize them for the web, while still allowing you to inspect each individual building. The source 3D data for the above example comes from Pennsylvania Spatial Data Access, with addresses, names, parcel numbers, and city-owned attributes from Open Data Philly.\nTo dive deeper into this visualization, we can use 3D Tiles Styling to highlight all properties owned by the City of Philadelphia and click on them to get their parcel numbers. The parcel number can then be used to look up more information about each building from the city database.\nYou can use 3D Tiles Styling to highlight all city-owned buildings in Philadelphia, such as museums and historic sites.\nTo create such a scene for a city, the source data should be one or more KML files that define the location of each 3D model. Here is a snippet from the KML file for Philadelphia buildings.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026lt;Placemark\u0026gt; \u0026lt;name\u0026gt;Independence Hall\u0026lt;/name\u0026gt; \u0026lt;Model\u0026gt; \u0026lt;Link\u0026gt;\u0026lt;href\u0026gt;building.dae\u0026lt;/href\u0026gt;\u0026lt;/Link\u0026gt; \u0026lt;!-- Model properties like longitude, latitude, etc... --\u0026gt; \u0026lt;/Model\u0026gt; \u0026lt;ExtendedData\u0026gt; \u0026lt;Data name=\u0026#34;Address\u0026#34;\u0026gt; \u0026lt;value\u0026gt;500-36 CHESTNUT ST\u0026lt;/value\u0026gt; \u0026lt;/Data\u0026gt; \u0026lt;Data name=\u0026#34;Parcel_ID\u0026#34;\u0026gt; \u0026lt;value\u0026gt;313762\u0026lt;/value\u0026gt; \u0026lt;/Data\u0026gt; \u0026lt;Data name=\u0026#34;Is_City_Owned\u0026#34;\u0026gt; \u0026lt;value\u0026gt;True\u0026lt;/value\u0026gt; \u0026lt;/Data\u0026gt; \u0026lt;/ExtendedData\u0026gt; \u0026lt;/Placemark\u0026gt; The Placemark name is used as the building name. Any additional data can be added to the tag.\nOnce you upload your buildings to Cesium ion, you can style and inspect them with Cesium Stories. You can also combine them with other types of content such as CityGML or point clouds, which can also have embedded feature data.\nTry creating a Cesium ion account and uploading your 3D buildings.\nAuthor: Omar Shehata\nOriginal link: https://cesium.com/blog/2020/04/09/kml-collada-metadata/\nComment: Cesium is relentlessly promoting Cesium ion and Cesium Stories. You might want to check them out, though personally I\u0026rsquo;m not a big advocate of online solutions since most people prefer offline setups. Data security is also increasingly important.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-04-10T07:13:20Z","permalink":"https://blog.coinidea.com/en/p/creating-3d-tiles-from-kml/collada-with-per-building-data/","title":"Creating 3D Tiles from KML/COLLADA with Per-Building Data"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCesium technology is revolutionizing the construction industry. The Smart Construction dashboard we developed in partnership with Komatsu enables us to visualize, measure, and analyze construction site progress faster than ever before. Here\u0026rsquo;s how it works.\nAggregating Different Datasets to Assess Progress To keep track, site managers must constantly compare the plans provided in CAD designs with what\u0026rsquo;s actually happening on site, which is captured by data from traditional surveys, drone surveys, and smart construction vehicles (including as-built data and vehicle telemetry).\nThe Cesium Tools application combines design models with time-stamped real-world data for measurement and progress tracking. Cesium takes these data sources as input, fuses them together to create an up-to-date 3D representation of the work site, and processes them into 3D Tiles so they can be easily shared and streamed.\nA DSM and orthoimagery converted into 3D Tiles, overlaid with vector data from line files created in CAD software packages.\nCollecting Data Building the smart construction application requires us to be ready to receive various data types, collected in different ways and at different levels of completeness.\nTraditional Surveys The traditional method of surveying a site uses a probe vehicle to take GPS measurements at a grid of positions across the work site. Collecting data this way takes a day or more, and the collected data is relatively sparse. This data can be compiled into 3D meshes in LandXML, DXF, or other triangle mesh formats.\nDrone Surveys Surveys can also be conducted by drones or UAVs. About once a week, for up to a day at a time, a drone flies over the site taking photos at multiple locations across the work site. Photogrammetry software converts these photos into an overall 3D model of the terrain. Common outputs include point clouds, DTM/DSM terrain data, and orthoimagery.\nA point cloud of a construction site in Osaka, Japan, collected by drone, converted into a mesh, and tiled into 3D Tiles by Cesium ion.\nDrone surveys are much faster than traditional surveys. For a company in the UK, adopting drone-based data collection combined with Cesium\u0026rsquo;s 3D tiling capabilities reduced the time from collection to visualization from 3 days to 30 minutes. The measurement results from each method had less than 2% error.\nSmart Construction Vehicles One of the latest trends in construction is machine tracking, either by embedding GPS sensors in construction equipment or attaching aftermarket sensors to them. These sensors track each machine as it moves around the site, providing \u0026ldquo;as-built\u0026rdquo; partial terrain data that, when merged with the existing ground, can provide a near real-time picture of the site terrain, typically collected on an hourly basis.\nThe yellow areas show recent \u0026ldquo;as-built\u0026rdquo; data collected from sensor-equipped construction machines, merged with an earlier drone survey of the entire site. Cesium lets you combine and visualize different surfaces at any point in time.\nBeyond Visualization While being able to see what\u0026rsquo;s happening is valuable, the real value of the Cesium Tools application lies in its analytics capabilities.\nA cut-and-fill analysis highlighted with a heatmap, showing how much earthwork needs to be moved and how much has already been moved.\nFor example, if a project manager needs to send results to a client for billing, they can understand the total percentage of earthwork that has been moved, as well as areas that still need work. Determining the amount of material remaining in inventory is as simple as clicking to create a measurement: the program calculates the volume, weight, and value of the material.\nMeasuring inventory.\nProject managers can also preview routes before traveling by clicking a path and inspecting the slope (as a heatmap or a profile using the 2D cross-section tool).\nTerrain slope heatmap.\nThis is just an overview of the many capabilities powered by Cesium in the Smart Construction app. Visit our construction industry page to watch the video and learn more.\nOriginal link: https://cesium.com/blog/2020/03/30/construction-with-cesium/\nAuthor: Gabby Getz\nComment: The tools and capabilities provided by the Cesium team are increasingly powerful and impressive.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-04-02T08:41:50Z","permalink":"https://blog.coinidea.com/en/p/using-cesium-tools-for-better-construction-management/","title":"Using Cesium Tools for Better Construction Management"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nWe created 3D Tiles to stream, visualize, and analyze massive 3D content, such as entire cities or complex building models. With the latest update to Cesium Stories, we can now inspect feature data in 3D Tiles by clicking.\nNow you can click on any 3D Tiles feature in Cesium Stories, such as the New York City tileset, to inspect its data.\nSuppose you want to learn about the distribution of medical facilities in New York City. You can use using styling to highlight all buildings in the 3D Tileset, then click to view facility capacity, whether there are emergencies, and their official websites and contact numbers.\nYou can also share your Cesium Story so other users can inspect it in the same way, whether they are doing a thorough analysis in the office or out in the field. On mobile devices, the info box can be collapsed or expanded to easily switch between the full 3D scene view and feature data.\nCesium Stories works in any modern web browser. On mobile devices, you can collapse or expand the info box to easily switch between the full 3D scene view and feature data.\nFeature picking in Cesium Stories works on any 3D Tileset with feature data and is not limited by the physical size of features, making it ideal for industries like BIM/CAD where you need to inspect everything from large pipes down to the smallest valves or screws.\nFeature picking in Cesium Stories works on any 3D Tileset with feature data, such as pipes and valves in a power plant BIM model.\nFeature picking also works with vector data, such as GeoJSON, KML, and CZML. Vector layers provide a simple way to add or update feature data, even if the 3D Tileset itself doesn\u0026rsquo;t contain any defined features.\nIn the example below, we took a Vricon photogrammetry tileset of Washington, D.C. from the Cesium Ion Asset repository that has no feature data, and combined it with building energy usage CZML from the Washington, D.C. Open Data platform.\nCombining energy usage CZML with Washington, D.C. photogrammetry allows us to click on any building to view its energy score. The CZML is customizable and can include building images.\nUsers can click on any building to view its name, annual energy consumption, and Energy Star score. KML and CZML support HTML descriptions, so you can add images, links, or customize the styling.\nWe\u0026rsquo;re excited to see what you\u0026rsquo;ll build with it. Learn how to use picking and styling in the Cesium Stories styling tutorial.\nOriginal link: https://cesium.com/blog/2020/03/25/explore-data-with-picking/\nAuthor: Omar Shehata\nComment: Cesium Stories is powerful and well worth trying.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2020-03-27T14:50:31Z","permalink":"https://blog.coinidea.com/en/p/inspecting-features-in-3d-tilesets-with-cesium-stories/","title":"Inspecting Features in 3D Tilesets with Cesium Stories"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\nCesium can be used to visualize data that changes over time, whether it\u0026rsquo;s geological changes spanning hundreds of years or satellite orbits that need to be tracked down to fractions of a second. As part of the official launch of Cesium Stories, we are pleased to announce improved support for time-dynamic data, so you can drag and drop dynamic KML or CZML to create interactive stories that visualize changing data.\nThis is a great way to review collected drone flight and telemetry data over time, as you can see the drone\u0026rsquo;s path \u0026ndash; across the entire world.\nWith Cesium Stories, we can review drone flight data alongside the surrounding landscape and view collected time-series telemetry data.\nAlternatively, if you perform offline analysis in tools like STK, you can export your work as CZML and easily share it with a link.\nSatellite coverage calculated by STK (System Tool Kit) and exported to Cesium Stories as a CZML file.\nTime-dynamic data doesn\u0026rsquo;t have to be objects moving over time. Our users have also plotted housing prices, disease outbreaks, and changing terrain maps.\nCesium Stories also supports dynamic KML files. This image shows the annual ice surface melt in Greenland from 1979 to 2007. Data from the National Snow and Ice Data Center.\nCesium Stories makes it easy to view and share your time-dynamic data, giving you control over playback speed and camera movement. Try it out with our new time-dynamic data tutorial. Or see what else you can do with Stories.\nOriginal link: https://cesium.com/blog/2020/03/04/time-dynamic-stories/\nAuthor: Omar Shehata\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\n","date":"2020-03-23T09:07:26Z","permalink":"https://blog.coinidea.com/en/p/visualizing-time-series-data-with-cesium-stories/","title":"Visualizing Time-Series Data with Cesium Stories"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\n3D Tiles was created to stream massive 3D datasets over the web. As an open specification, it is intended to serve as the de facto standard for visualizing and analyzing large 3D data across many different runtime engines. Today, many engines, including CesiumJS, AGI\u0026rsquo;s STK, and Uber\u0026rsquo;s loaders.gl, support 3D Tiles for streaming massive 3D geospatial datasets.\nWe are excited to announce the release of 3D Tiles Overview, an easy-to-follow guide for learning the main concepts of 3D Tiles, designed to help integrate 3D Tiles support into runtime engines for visualizing and analyzing large heterogeneous 3D geospatial content.\nThe cover page of the 3D Tiles Overview highlights all the concepts covered.\nThis guide complements the detailed and comprehensive 3D Tiles specification with concise coverage of key concepts to help developers get started with 3D Tiles quickly.\nWe are thrilled to have collaborated with Marco Hutter, a long-time contributor to glTF and the creator of the glTF reference card that inspired this work.\nWe would love to learn how the 3D Tiles Overview helps developers work with 3D Tiles and whether there are any suggestions for improvement. If you\u0026rsquo;re looking for a place to learn 3D Tiles, head to Cesium ion to curate your own 3D Tilesets, or upload your own data for tiling, hosting, and streaming as 3D Tiles.\nAuthor: Shehzan Mohammed\nOriginal link: https://cesium.com/blog/2020/03/12/3d-tiles-overview/\nNote: 3D Tiles Overview is an introductory guide to 3D Tiles produced by the official Cesium team and is highly recommended for learning.\nGitHub link: 3D Tiles Overview\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\n","date":"2020-03-21T07:38:56Z","permalink":"https://blog.coinidea.com/en/p/learning-3d-tiles-with-3d-tiles-overview/","title":"Learning 3D Tiles with 3D Tiles Overview"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\nEdgyGeo, Inc. has done some fantastic work supporting the Architecture, Engineering, and Construction (AEC) industry. This time let\u0026rsquo;s take a look at their download tool, which allows architects, engineers, developers, and urban planners to quickly obtain massive datasets for specified areas.\n3D buildings and routes in a single scene. Dataset from Los Angeles.\nWith the Cesium-based viewer, EdgyGeo allows users to explore entire cities. The highlight of their data is high-resolution CyberCity 3D buildings, automatically generated through photogrammetric modeling. Their high-resolution building library covers nearly 100 cities in the United States and dozens of other major cities worldwide, with extruded buildings available for additional locations.\nBut EdgyGeo offers more than just buildings. They have datasets from state and local governments (especially cities), utilities, airports, commercial real estate companies, downtown development associations, and third-party entities. These datasets include terrain, environmental data, FEMA flood data, and other GIS data. Subscribers can also add their own data assets and build data inventories.\nEdgyGeo collects and curates this data. Using Cesium\u0026rsquo;s 3D tiling pipeline, they stitch these datasets into 3D Tiles and fuse them in Cesium ion, so no matter how large the collected data is, it can be efficiently streamed and easily explored on a map with 3D terrain and imagery.\nCesium\u0026rsquo;s 3D tiling pipeline allows EdgyGeo to share large datasets online simultaneously.\nNot only are the scenes easy to browse, but users can also download data for their own projects. Users simply select a portion of the scene and download the data in that area. They can download multiple GIS datasets at once, including CyberCity 3D building models, 3D terrain, aerial imagery, centerlines, curbs, and more \u0026ndash; all precisely geolocated.\nIt\u0026rsquo;s easy to find and select relevant datasets for a specific area, such as Cambridge, MA.\nDownloads are available in Collada (DAE) and KML/KMZ formats, and users can upload them to their own Cesium ion accounts or visualize them in other applications such as Rhino, SketchUp, and Revit at any time. KML format will also soon become available.\n3D geometry exported from EdgyGeo visualized in SketchUp.\nWith this customizable download option, subscribers can obtain the local datasets needed for specific projects, linking GIS, AEC, BIM, and construction tools in a simple data download and transfer process.\nYou can try the tool by contacting EdgyGeo CEO Kevin DeVito.\nAuthor: Sarah Chow\nOriginal link: https://cesium.com/blog/2020/03/03/edgygeo-3d-tiles-download/\nComment: Cesium ion appears to be the officially recommended data storage and management tool from Cesium. Looking at future developments, we recommend using the download tool described in this article along with Cesium ion.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\n","date":"2020-03-19T02:31:00Z","permalink":"https://blog.coinidea.com/en/p/using-edgygeo-cesium-tools-to-query-and-download-datasets/","title":"Using EdgyGeo Cesium Tools to Query and Download Datasets"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\nWith travel restrictions from Europe to the United States taking effect today, and with increasing encouragement for people to stay home to slow the spread of the coronavirus, we were curious how these measures are affecting global travel. Naturally, we used Cesium to explore.\nWe began collecting flight data every other day over the past few months. Here are all the flights in and out of Beijing\u0026rsquo;s main international airport:\n[The number of scheduled flights at Beijing Capital International Airport (PEK) visualized over time. Departures are shown in red, arrivals in green.]\nAt the end of January, the number of flights dropped sharply, from about 900 flights rapidly down to fewer than 300. This coincided with the World Health Organization (WHO) declaring a global health emergency and the United States and other countries restricting travel from China.\nFollowing China, Italy was severely affected by the coronavirus. The first reported case occurred on February 22, cases surged rapidly, and the Italian government implemented a quarantine on March 8. We can see flight traffic declining there, though not as rapidly:\n[Flights in and out of Rome\u0026rsquo;s Leonardo da Vinci-Fiumicino Airport (FCO) in Italy.]\nAs of the time of writing, flights in London had not been subject to any official restrictions, but scheduled flights for the remainder of March still showed a significant decline. We marked all US flights in red.\n[Flights in and out of London Heathrow Airport.]\nFinally, here is JFK Airport in New York City, one of the largest air traffic hubs in the United States. So far, there didn\u0026rsquo;t appear to be any significant changes:\n[Flights in and out of New York\u0026rsquo;s John F. Kennedy International Airport.]\nHow We Created These Visualizations Flight data was obtained from AeroDataBox. Their API takes an airport code parameter and returns all flights in and out of that airport within a given time period.\nOnce we had these scheduled routes, we used open data from OpenFlights to get the location of each airport.\nFinally, we created a CZML that draws a line for each route with a timestamp, and visualized the routes over time using Cesium Stories.\nIf readers want to create something similar, we recommend starting with the Cesium Stories time-dynamic data tutorial.\nOriginal author: Omar Shehata\nLink: https://cesium.com/blog/2020/03/13/covid-19-flight-impact/\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\n","date":"2020-03-16T15:27:10Z","permalink":"https://blog.coinidea.com/en/p/exploring-the-impact-of-covid-19-on-global-flights/","title":"Exploring the Impact of COVID-19 on Global Flights"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public: int findComplement(int num) { int countDigit = 0; int numBak = num; while (0 \u0026lt; num) { num = num \u0026gt;\u0026gt; 1; countDigit++; } return (int)(pow(2, countDigit) - 1 - numBak); } }; ","date":"2020-03-09T13:54:50Z","permalink":"https://blog.coinidea.com/en/p/leetcodenumber-complement/","title":"[leetcode]Number Complement"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Foo { private: bool isFirst; bool isSecond; bool isThird; public: Foo() { isFirst = false; isSecond = false; isThird = true; } void first(std::function\u0026lt;void()\u0026gt; printFirst) { while (!isThird); isThird = false; isSecond = false; printFirst(); // printFirst() outputs \u0026#34;first\u0026#34;. Do not change or remove this line. isFirst = true; } void second(std::function\u0026lt;void()\u0026gt; printSecond) { while(!isFirst); isFirst = false; isThird = false; // printSecond() outputs \u0026#34;second\u0026#34;. Do not change or remove this line. printSecond(); isSecond = true; } void third(std::function\u0026lt;void()\u0026gt; printThird) { while(!isSecond); isFirst = false; isSecond = false; // printThird() outputs \u0026#34;third\u0026#34;. Do not change or remove this line. printThird(); isThird = true; } }; ","date":"2020-02-23T04:11:23Z","permalink":"https://blog.coinidea.com/en/p/leetcodeprint-in-order/","title":"[leetcode]Print in Order"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\nIt has been a while since I last updated the official account and knowledge community. Over the past three months, I made many life-changing decisions. I had already joined a state-owned enterprise, fully engaged in smart city engine development. Then, by a twist of fate, I ended up joining Microsoft (Asia) Internet Engineering Academy (STCA) to work on big data R\u0026amp;D. Life is unpredictable. There are no right or wrong choices, only choices. If anyone has questions about job hunting, resumes, interviews, or recruitment in technical positions, feel free to reach out to me.\nBut rest assured, I will continue to follow data visualization and Cesium. Currently, I am very optimistic about the Cesium project, as well as IoT and smart cities.\nIn the coming period, I will strive to update the official account weekly and the knowledge community monthly. I will try to keep the content concise and informative, and I hope it will be helpful to everyone. If you have any suggestions or feedback for the Cesium Chinese Website, feel free to leave me a message.\nRecent Cesium Updates:\nCesium continues to maintain its monthly release schedule at the beginning of each month, but there was apparently a mistake in November 2019 that resulted in two releases that month. As of now (December 9, 2019), Cesium has been updated to Cesium-1.64. Here is the update list:\n1.64 – 2019-12-02: Cesium-1.64.zip introduces a large number of internal optimizations.\n1.63.1 – 2019-11-06: Cesium-1.63.1.zip fixes an issue in 1.63 where the globe surface and labels rendered incorrectly when window.devicePixelRatio was set to greater than 1.0.\nFixes an issue in 1.63 where some primitives would show through the globe when log depth was disabled.\n1.63 – 2019-11-01: Cesium-1.63.zip Cesium migrates to ES6 modules. This may affect your Cesium application depending on how you use Cesium.\nAll website content from cesiumjs.org and cesium.com has been consolidated into cesium.com.\nAdded UTF-8 support for labels, greatly improving support for non-Latin characters and emojis.\n10x compression of the Web Workers bundle size, from 8384KB (2624KB compressed) to 863KB (225KB compressed). This improves Cesium loading speed, especially on low-performance devices and high-latency networks.\nDomestic Source Code Download Links (200KB/S)\nGiven that download speeds for Released versions on GitHub are very unstable (even though GitHub has been acquired by Microsoft), the Cesium Chinese Website provides mirror download links for recent Cesium versions. However, due to server and bandwidth costs, we cannot guarantee that all historical versions will be available for download, nor can we guarantee great download speeds. Actual tests show 100~200KB/S.\nDownload Link:\nhttp://cesium.coinidea.com/site/download.html\nCesium Chinese Website QQ Group: 807482793 Cesium Chinese Website: http://cesiumcn.org/ | Fast Domestic Access: http://cesium.coinidea.com/\n","date":"2019-12-09T01:31:00Z","permalink":"https://blog.coinidea.com/en/p/recent-cesium-updates-and-domestic-source-code-download-links/","title":"Recent Cesium Updates and Domestic Source Code Download Links"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Access in China: http://cesium.coinidea.com/\nCesium Chinese Website: http://cesiumcn.org/ | Fast Access in China: http://cesium.coinidea.com/\nIDE Web front-end beginners often want to choose a fast, easy-to-use, and popular (I\u0026rsquo;m not sure why it needs to be popular exactly \u0026ndash; perhaps engineers want to stay on the mainstream path in their technical journey?) IDE (Integrated Development Environment). Is an IDE important? It is both important and not important. It\u0026rsquo;s not important because: it\u0026rsquo;s just a tool, and we should focus more on requirements, logic, algorithms, and knowledge. It\u0026rsquo;s important because: it is a tool, and as the old saying goes, \u0026ldquo;A craftsman must first sharpen his tools to do his work well\u0026rdquo; \u0026ndash; choosing the right tool often yields twice the result with half the effort.\nThe CesiumJS official team does not specifically recommend an IDE, but in the introductory tutorial Cesium Getting Started 2 - Setting Up the Cesium Environment and Your First Sample Program, there is this passage:\nIf you're already a seasoned developer, you most likely have a favorite editor or development environment; for example, most of the Cesium team uses Eclipse. If you're just starting out, a great free and open-source editor is Notepad++, which you can download from their website. Ultimately any text editor will do, so go with the one that you are most comfortable with. As we can see, the Cesium team primarily uses the open-source Eclipse or recommends Notepad++.\nBased on the author\u0026rsquo;s own experience, here is a brief list of IDEs I have used:\nNotepad (built-in on Windows) or TextEdit (built-in on Mac)\nPrice: Free\nDownload: Built into the system\nStartup speed: Extremely fast\nOperating system: Windows/Mac\nNotepad is the basic text editor. Every engineer\u0026rsquo;s (Note: from now on, the author will refer to programmers as engineers \u0026ndash; respect yourself to earn respect) ultimate dream is to code with a plain text editor, which is cool but very difficult. You can use Notepad to read simple HTML, JavaScript, or CSS files, but it is not recommended for development at all.\nIf you have systematically studied computer science, you are certainly familiar with compiling, linking, building, testing, etc. (although front-end development rarely involves compiling and linking). A good IDE must provide excellent project organization. Notepad cannot do this.\nNotepad++ (For Windows only)\nPrice: Free\nDownload: https://notepad-plus-plus.org/downloads/\nStartup speed: Extremely fast\nOperating system: Windows\nAn excellent ultra-lightweight editor. In addition to reading and writing HTML, JavaScript, or CSS, it supports opening folders, which provides some level of project organization. It has a large number of plugins available. Currently, as far as the author knows, it only supports the Windows environment.\nSublime Text (For Windows and Mac)\nPrice: Paid, closed-source\nDownload: www.sublimetext.com/ (Official) | http://www.sublimetext.cn/ (Chinese Community)\nStartup speed: Fast\nOperating system: Windows/Mac\nAn excellent lightweight editor. It covers almost all the features of Notepad++, while supporting both Windows and Mac. It has a massive plugin ecosystem.\nNew features include: GOTO ANYTHING, GOTO DEFINITION, multiple selection, command palette, customization, split editing, instant project switching, and more. Of course, you can also use the unregistered version without paying.\nEclipse/MyEclipse (For Windows and Mac)\nPrice: Free/Paid\nDownload: https://www.eclipse.org/downloads/\nStartup speed: Medium/Slow\nOperating system: Windows/Mac\nMyEclipse is actually a paid version of Eclipse, which originally existed as a plugin. Eclipse is primarily a Java IDE that integrates Java-related plugins very well. If your back-end technology choice is Java when developing with Cesium, and you prefer using a free IDE without being too concerned about front-end and back-end separation, then Eclipse is an excellent choice.\nPHPStorm/IntelliJ IDEA/WebStorm (For Windows and Mac)\nPrice: Paid\nDownload: http://www.jetbrains.com/phpstorm/ | http://www.jetbrains.com/idea/ | http://www.jetbrains.com/webstorm/\nStartup speed: Slow\nOperating system: Windows/Mac\nAs you can tell from the domain, these three IDEs come from the same company. They are excellent IDEs, but they are all quite expensive and require annual license purchases. If you have the budget, you can purchase them. They are truly outstanding. Among them, if your back-end choice is PHP when developing with Cesium, you can use PHPStorm; if your back-end choice is Java, you can use IntelliJ IDEA; if you only need to develop web front-end code, have a decent computer, and are willing to pay, you can use WebStorm. As the old saying goes: \u0026ldquo;You get what you pay for\u0026rdquo; \u0026ndash; they are expensive because they are genuinely good.\nVisual Studio Code (VSCode) (For Windows and Mac)\nPrice: Free\nDownload: https://code.visualstudio.com/\nGitHub: https://github.com/Microsoft/vscode\nStartup speed: Fast\nOperating system: Windows/Mac\nIs cheap really synonymous with low quality? Not at all. Allow me to introduce the most powerful IDE in the universe: VSCode. When I was interning at MSRA, I kept thinking that since Visual Studio could be made so excellent, could there be a similarly excellent IDE for front-end development like Visual Studio? Yes, there is \u0026ndash; Microsoft\u0026rsquo;s own child, the free, open-source, and cross-platform Visual Studio Code. It must be said that Microsoft has done a lot in embracing open source in recent years.\nFree. Built on open source. Runs everywhere. VSCode can be used not only for front-end development, but also for Java, PHP, C++, Python, and more.\nPlugin marketplace: https://marketplace.visualstudio.com\nVSCode is not inferior to WebStorm in any aspect. VSCode has an excellent plugin ecosystem. It has all the features a great IDE should have: IntelliSense, front-end support, auto-fix (plugins), Git/GitHub integration (GitLens), history (Local History), code checking (Code Spell Checker), themes, color schemes, and more.\nGetting Started with Visual Studio Code 1. Command Palette You can open it with F1 or Ctrl (Cmd on Mac) + Shift + P.\nType in the box: \u0026gt;Extensions: Show Installed Extensions to view installed plugins. You can also enter other commands.\n2. How to Install Plugins Installing the Live Server Plugin Click on Extensions in the left toolbar, type \u0026ldquo;live server\u0026rdquo; (or any other plugin name) in the search box, and you will see the first plugin named:\nLive Server. Click Install to install the plugin.\nWhat this plugin does: It has a built-in web server (Live Server) that allows you to preview your changes at any time during development without worrying too much about the web server.\nRight-click \u0026ldquo;Open With Live Server\u0026rdquo; to open the corresponding Cesium page in the browser: 3. Commonly Used Plugins Settings Sync: Synchronize VSCode settings\nDebugger for Chrome: Debug JavaScript code running in Google Chrome from VS Code\nbeautify: Format code\nAuto Rename Tag: Automatically synchronize modifications of opening and closing tags\nguides: Code alignment guide lines\nfilesize: Display current file size, creation and modification time\nTodo Tree: Quickly search for TODO and other comment markers\nvetur/VueHelper: Vue plugins\nHTML Snippets: Provides basic H5 code snippets and tags\nHTML CSS Support: Provides intelligent suggestions for CSS styles when writing class attributes in HTML tags\nvscode-icon: Adds corresponding icons to VSCode folder directories. (If it does not take effect, go to [File - Preferences - File Icon Theme] to re-select the setting)\npath intellisense: File path auto-completion\nnpm intellisense: Auto-completion for package references in require statements\nbracket pair colorizer: Gives brackets independent colors\ntortoiseSvn: SVN plugin\nauto close tag: Automatically adds HTML/XML closing tags\nchange-case: More naming format options for text, such as camelCase, underscore_separated, etc.\ncolor info: Hover over a color to preview detailed color model information in the color block\ncss peek: Navigate to CSS class and ID definitions in stylesheets. In the HTML file right-click menu, clicking on a selector and selecting \u0026ldquo;Go to Definition\u0026rdquo; will jump to the CSS code\neslint: Checks for syntax errors in JavaScript code\nhtml boilerplate: HTML template plugin, create an HTML file with one click\nhtmlHint: HTML code format checking\nintelliSense for CSS class names in HTML: Provides intelligent suggestions in HTML from CSS class names found in project CSS files\nJavaScript (ES6) code snippets: ES6 code snippet suggestions\nThe above plugins can be found and installed directly by searching in the Extensions marketplace.\n4. Chinese Language Pack Chinese (Simplified) Language Pack for Visual Studio Code \u0026ndash; for readers who prefer Chinese, you can download and install this Simplified Chinese language pack.\nAfter installation, restart VSCode:\nThere are many bloggers online who have written detailed guides on how to use Visual Studio Code. You can search for them using your preferred search engine. You can also leave a comment on the Cesium Chinese Website (http://cesium.coinidea.com/).\nCesium Chinese Website QQ Group: 807482793 Cesium Chinese Website: http://cesiumcn.org/ | Fast Access in China: http://cesium.coinidea.com/\n","date":"2019-10-22T15:01:55Z","permalink":"https://blog.coinidea.com/en/p/part-1-sharpen-your-cesium-tools-visual-studio-code/","title":"[Part 1] Sharpen Your Cesium Tools - Visual Studio Code"},{"content":"We have now launched Knowledge Planet - Friends of the Cesium Chinese Website.\nNote: Please think carefully before joining. Once paid, no refunds will be given. The following content is provided on a best-effort basis. 1. One technical exchange session per month (primarily Cesium-related), with source code provided.\n2. Each person gets 5 free questions per week (Cesium, data visualization, and other technical topics).\n3. Resume review and job referrals.\n4. Career planning available for an additional fee.\nThe tentative exchange topics are as follows: [Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime. The key goal is to help everyone develop the ability to independently research and develop related frameworks**]; we hope this will be helpful to you.\nConsidering everyone\u0026rsquo;s actual situation, we may briefly cover: operating systems, computer networks, HTML/CSS/JavaScript, object-oriented programming, and basic principles of 3D digital earth.\nBeing able to use basic Git commands, download code from open-source communities, and run Cesium.\nLoading and manipulating images, terrain, and models in Cesium.\nWhether you can crawl your own tile map data; how to write lightweight crawling tools.\nHow to build your own GIS data server through GeoServer, and 2D data display with OpenLayers.\nCross-platform web, human-computer interaction events in Cesium, and how to achieve synchronization across browsers or devices within a local network.\nOther topics that may be covered: Cesium with Echarts and Vue, other GIS systems, and some data visualization content.\n","date":"2019-07-15T07:28:08Z","permalink":"https://blog.coinidea.com/en/p/friends-of-the-cesium-chinese-website/","title":"Friends of the Cesium Chinese Website"},{"content":"Azkaban is an open-source task scheduling system used for scheduling and running tasks (such as data warehouse scheduling), serving as a replacement for crontab in Linux. Official website: https://azkaban.github.io/\nAzkaban mainly consists of three components:\nMySQL: Azkaban uses MySQL to store projects and execution information. Azkaban Web Server: Azkaban uses Jetty as the web server, serving as the controller and providing the web interface. Azkaban Executor Server: The Azkaban executor server executes submitted workflows. This article primarily uses Azkaban 3.43. If you need help generating compiled tar packages from GitHub source code, feel free to leave a comment, and I can share the installation package files that I have already tested.\nThe installation package files mainly include:\nazkaban-db-3.43.0.tar.gz azkaban-solo-server-3.43.0.tar.gz azkaban-exec-server-3.43.0.tar.gz azkaban-web-server-3.43.0.tar.gz azkaban-hadoop-security-plugin-3.43.0.tar.gz\nAmong these, solo is the standalone version. I set up a version with multiple executor nodes and a single web server node. Note: This article assumes the Azkaban directory is located at /azkaban.\nDatabase\nFirst, you need to install the MySQL database, then create a database called azkaban. Execute the following in MySQL:\nsource /azkaban/azkaban-db/create-all-sql-0.1.0-SNAPSHOT.sql Configuration Files\n0. Configure the keystore. The keystore is located at /azkaban/azkaban-web/conf/ (the path must match the one in the configuration file).\nkeytool -keystore keystore -alias jetty -genkey -keyalg RSA Enter keystore password: azkaban Re-enter new password: azkaban What is your first and last name? [Unknown]: Skip What is the name of your organizational unit? [Unknown]: Skip What is the name of your organization? [Unknown]: Skip What is the name of your City or Locality? [Unknown]: Skip What is the name of your State or Province? [Unknown]: Skip What is the two-letter country code for this unit? [Unknown]: CN Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=CN correct? [no]: Y Enter key password for (RETURN if same as keystore password): /azkaban/azkaban-web/conf/azkaban.properties # Azkaban Personalization Settings azkaban.name=Allin azkaban.label=My Local Azkaban azkaban.color=#FF3601 azkaban.default.servlet.path=/index web.resource.dir=/azkaban/azkaban-web-server/web/ default.timezone.id=Asia/Shanghai # Azkaban UserManager class user.manager.class=azkaban.user.XmlUserManager user.manager.xml.file=/azkaban/azkaban-web-server/conf/azkaban-users.xml # Loader for projects executor.global.properties=/azkaban/azkaban-web-server/conf/global.properties azkaban.project.dir=/azkaban/azkaban-web-server/projects # Velocity dev mode velocity.dev.mode=false # Azkaban Jetty server properties. jetty.use.ssl=false jetty.maxThreads=25 jetty.port=8443 jetty.keystore=//azkaban/azkaban-web-server/conf/keystore jetty.password=yourpassword jetty.keypassword=yourpassword jetty.truststore=//azkaban/azkaban-web-server/conf/keystore jetty.trustpassword=yourpassword # Azkaban Executor settings executor.port=12321 # mail settings mail.sender= mail.host= # User facing web server configurations used to construct the user facing server URLs. They are useful when there is a reverse proxy between Azkaban web servers and users. # enduser -\u003e myazkabanhost:443 -\u003e proxy -\u003e localhost:8081 # when this parameters set then these parameters are used to generate email links. # if these parameters are not set then jetty.hostname, and jetty.port(if ssl configured jetty.ssl.port) are used. # azkaban.webserver.external_hostname=myazkabanhost.com # azkaban.webserver.external_ssl_port=443 # azkaban.webserver.external_port=8081 job.failure.email= job.success.email= lockdown.create.projects=false cache.directory=cache # JMX stats jetty.connector.stats=true executor.connector.stats=true # Azkaban plugin settings azkaban.jobtype.plugin.dir=/azkaban/azkaban-web-server/plugins/jobtypes database.type=mysql mysql.port=3306 mysql.host=127.0.0.1 mysql.database=azkaban mysql.user=root mysql.password=yourmysqlpassword mysql.numconnections=100 /azkaban/azkaban-exec/conf/azkaban.properties # Azkaban Personalization Settings default.timezone.id=Asia/Shanghai # Loader for projects executor.global.properties=/azkaban/azkaban-exec-server/conf/global.properties azkaban.project.dir=/azkaban/azkaban-exec-server/projects azkaban.jobtype.plugin.dir=/azkaban/azkaban-exec-server/plugins/jobtypes database.type=mysql mysql.port=3306 mysql.host=127.0.0.1 mysql.database=azkaban mysql.user=root mysql.password=yourpassword mysql.numconnections=100 # Azkaban Executor settings executor.maxThreads=50 executor.port=12321 executor.flow.threads=30 /azkaban/azkaban-web/conf/log4j.properties /azkaban/azkaban-exec/conf/log4j.properties log4j.rootLogger=INFO,C log4j.appender.C=org.apache.log4j.ConsoleAppender log4j.appender.C.Target=System.err log4j.appender.C.layout=org.apache.log4j.PatternLayout log4j.appender.C.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n For multiple executor nodes, you need to add the following configuration to /azkaban/azkaban-web/conf/azkaban.properties, and insert the IP addresses and port numbers of the corresponding executor nodes into the database. azkaban.use.multiple.executors=true azkaban.executorselector.filters=StaticRemainingFlowSize,MinimumFreeMemory,CpuStatus azkaban.executorselector.comparator.NumberOfAssignedFlowComparator=1 azkaban.executorselector.comparator.Memory=1 azkaban.executorselector.comparator.LastDispatched=1 azkaban.executorselector.comparator.CpuUsage=1 Insert executor node IP addresses and port numbers:\ninsert into executors(host,port) values(\"your ip1\",12321); insert into executors(host,port) values(\"your ip2\",12321); Configure username and password at /azkaban/azkaban-web/conf/azkaban-users.xml\nWith basic computer knowledge, opening this configuration file is self-explanatory.\nCreate log directories\nmkdir /azkaban/azkaban-web/logs mkdir /azkaban/azkaban-exec/logs Start the services azkaban/azkaban-exec/bin/start-exec.sh azkaban/azkaban-web/bin/start-web.sh Common Pitfalls\nThe keystore location must match the file path set in the configuration file. Azkaban 3 and above supports multiple executor nodes. The startup method in step 7 runs in silent mode. During initial testing, it is recommended to use: azkaban/azkaban-exec/bin/azkaban-web-start.sh azkaban/azkaban-exec/bin/azkaban-exec-start.sh This way you can see whether errors occur and what causes them.\n4. Based on error messages, you may not have correctly created the logs directory or the path may be incorrect.\n5. Since the web server checks the exec server, it is recommended to start the exec server first.\n6. If tasks are not executing in a multi-node setup, it may be because the executor nodes have insufficient resources. Check the configuration carefully. The configuration specifies under what memory, CPU, and other resource conditions the server will execute tasks, and how executor nodes are assigned if no specific node is designated. If you do not want to limit resources, modify or comment out the relevant configuration.\nazkaban.use.multiple.executors=true azkaban.executorselector.filters=StaticRemainingFlowSize,MinimumFreeMemory,CpuStatus azkaban.executorselector.comparator.NumberOfAssignedFlowComparator=1 azkaban.executorselector.comparator.Memory=1 azkaban.executorselector.comparator.LastDispatched=1 azkaban.executorselector.comparator.CpuUsage=1 How to specify a node to execute a job:\nSet \u0026ldquo;useExecutor\u0026rdquo; = EXECUTOR_ID in the flow params.\nFor details, please refer to:\nhttps://www.jianshu.com/p/ffb7bbc1988f ","date":"2019-06-15T00:47:43Z","permalink":"https://blog.coinidea.com/en/p/azkaban-open-source-task-scheduling-system/","title":"AZKABAN - Open Source Task Scheduling System"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Access in China: http://cesium.coinidea.com/\nwebpack is a popular and powerful tool for bundling JavaScript modules. It allows developers to structure code and assets in an intuitive way, and load different types of files as needed using simple require statements. During build time, it tracks code dependencies and bundles these modules into one or more bundles for the browser to load.\nIn the first half of this tutorial, we set up a simple web application using webpack from scratch, then cover the subsequent steps to integrate the Cesium npm module. If you like developing web applications with CesiumJS, webpack is a great choice. If you are new to Cesium and looking to learn how to build your first sample application, please check the Getting Started Tutorial.\nIn the second part, we will explore more advanced webpack configurations to optimize applications using CesiumJS.\nThe complete code and tips for optimizing a CesiumJS webpack application can be found in the official cesium-webpack-example.\nPrerequisites Basic understanding of the command line, JavaScript, and web development. An IDE or code editor. Cesium team developers use Visual Studio Code, but a minimal code editor such as Sublime Text works perfectly fine as well. Node.js installed. We recommend using the latest LTS version. Create a basic webpack app In this section, we will cover how to set up a basic web application with webpack and a development server. If you already have an application set up and just want to add CesiumJS, skip to Add CesiumJS to a webpack app.\nInitialize an app with npm Create a new cesium-webpack directory for your app. Open the console, navigate to the new directory, and run the following command:\n1 npm init Follow the prompts and fill in all the details about your application. Press enter to use the default values. This will create package.json.\nCreate the app code Create a src directory for our application code. When we build the application, webpack will generate distribution files in the dist directory.\nCreate src/index.html and add the boilerplate HTML page code.\n1 2 3 4 5 6 7 8 9 10 11 12 13 \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; \u0026lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=edge\u0026#34;\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Hello World!\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Hello World!\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Next, create an entry point for the application. This is the entry point where webpack looks for all JavaScript source code and dependencies to bundle.\nCreate src/index.js and add the following code:\n1 console.log(\u0026#39;Hello World!\u0026#39;); Install and configure webpack Start by installing webpack:\n1 npm install --save-dev webpack Configuration Create webpack.config.js to define the webpack configuration object.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 const path = require(\u0026#39;path\u0026#39;); const webpack = require(\u0026#39;webpack\u0026#39;); module.exports = { context: __dirname, entry: { app: \u0026#39;./src/index.js\u0026#39; }, output: { filename: \u0026#39;[name].js\u0026#39;, path: path.resolve(__dirname, \u0026#39;dist\u0026#39;), } }; context specifies the base path for the files. entry is used to specify the bundles. In this case, the entry point for the app bundle is src/index.js. webpack will output the bundled app.js to the dist folder.\nLoaders Webpack loads everything like a module. Use loaders to load CSS and other asset files. Install style-loader, css-loader, and url-loader.\n1 npm install --save-dev style-loader css-loader url-loader Add two module.rules in webpack.config.js: one for CSS files and another for other static files. For each rule, test defines the file types to load, and use specifies the list of loaders.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const path = require(\u0026#39;path\u0026#39;); const webpack = require(\u0026#39;webpack\u0026#39;); module.exports = { context: __dirname, entry: { app: \u0026#39;./src/index.js\u0026#39; }, output: { filename: \u0026#39;[name].js\u0026#39;, path: path.resolve(__dirname, \u0026#39;dist\u0026#39;), }, module: { rules: [{ test: /\\.css$/, use: [ \u0026#39;style-loader\u0026#39;, \u0026#39;css-loader\u0026#39; ] }, { test: /\\.(png|gif|jpg|jpeg|svg|xml|json)$/, use: [ \u0026#39;url-loader\u0026#39; ] }] } }; Plugins Define index.html and inject the bundle into this page using a webpack plugin called html-webpack-plugin.\n1 npm install --save-dev html-webpack-plugin Reference the plugin in webpack.config.js, then inject it into plugins. Pass src/index.html as our template.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const path = require(\u0026#39;path\u0026#39;); const webpack = require(\u0026#39;webpack\u0026#39;); const HtmlWebpackPlugin = require(\u0026#39;html-webpack-plugin\u0026#39;); module.exports = { context: __dirname, entry: { app: \u0026#39;./src/index.js\u0026#39; }, output: { filename: \u0026#39;[name].js\u0026#39;, path: path.resolve(__dirname, \u0026#39;dist\u0026#39;), }, module: { rules: [{ test: /\\.css$/, use: [ \u0026#39;style-loader\u0026#39;, \u0026#39;css-loader\u0026#39; ] }, { test: /\\.(png|gif|jpg|jpeg|svg|xml|json)$/, use: [ \u0026#39;url-loader\u0026#39; ] }] }, plugins: [ new HtmlWebpackPlugin({ template: \u0026#39;src/index.html\u0026#39; }) ] }; The configuration file is a JavaScript file, so we can require other Node modules and perform operations.\nBundle the app Use package.json to define scripts that can be called with npm. Add a build command.\n1 2 3 \u0026#34;scripts\u0026#34;: { \u0026#34;build\u0026#34;: \u0026#34;node_modules/.bin/webpack --config webpack.config.js\u0026#34; } This script calls webpack and passes in the webpack.config.js configuration file.\nWe use local installations of webpack and webpack-dev-server in these scripts. This allows each project to use its own separate version, which is recommended by the webpack documentation. If you prefer to use a global version, install it globally with npm install \u0026ndash;global webpack, and run it with the command webpack \u0026ndash;config webpack.config.js.\nWhen you run the build command: npm run build\nYou should see some output from webpack, starting with the following:\n1 2 3 4 5 6 7 8 9 10 11 npm run build \u0026gt; test-app@1.0.0 build C:\\workspace\\test-app \u0026gt; node_modules/.bin/webpack --config webpack.config.js Hash: 2b42bff7a022b5d956a9 Version: webpack 3.6.0 Time: 2002ms Asset Size Chunks Chunk Names Assets/Textures/NaturalEarthII/2/0/3.jpg 10.3 kB [emitted] app.js 162 kB 0 [emitted] app The app.js bundle and index.html file will be output to the dist folder.\nRun the development server Use webpack-dev-server to serve the development build so we can see our app in action:\n1 npm install --save-dev webpack-dev-server Add a start script in package.json to run the development server. Set the configuration file via the \u0026ndash;config flag. Use the \u0026ndash;open flag to open the application in the browser when the command is executed.\n1 2 3 4 \u0026#34;scripts\u0026#34;: { \u0026#34;build\u0026#34;: \u0026#34;node_modules/.bin/webpack --config webpack.config.js\u0026#34;, \u0026#34;start\u0026#34;: \u0026#34;node_modules/.bin/webpack-dev-server --config webpack.config.js --open\u0026#34; } Tell the development server to serve files from the dist folder. Add this to the bottom of webpack.config.js.\n1 2 3 4 // development server options devServer: { contentBase: path.join(__dirname, \u0026#34;dist\u0026#34;) } Finally, run the app:\n1 npm start You should see your content rendered at localhost:8080, and see the \u0026ldquo;Hello World!\u0026rdquo; message when you open the browser console.\nAdd CesiumJS to a webpack app Install CesiumJS Install the cesium module from npm and add it to package.json.\nConfigure CesiumJS in webpack CesiumJS is a large and complex library. In addition to JavaScript modules, it also includes static assets such as CSS, image, and JSON files. It includes web worker files to perform intensive computations in separate threads. Unlike traditional npm modules, CesiumJS does not define an entry point because the library can be used in many different ways. We need to configure some additional options for use with webpack.\nFirst, define the location of CesiumJS. This tutorial is based on the source code, so webpack can include individual models and track dependencies. Alternatively, the built (minified or unminified) versions of CesiumJS can be used. However, these modules have already been combined and optimized, which gives us less flexibility.\nAdd the following code to the top of webpack.config.js:\n1 2 3 // The path to the CesiumJS source code const cesiumSource = \u0026#39;node_modules/cesium/Source\u0026#39;; const cesiumWorkers = \u0026#39;../Build/Cesium/Workers\u0026#39;; This tutorial uses the npm module for easy installation, but you can also clone the GitHub repository or download and extract a release version.\nAdd the following options to the configuration object to resolve some issues with how webpack compiles CesiumJS.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 output: { filename: \u0026#39;[name].js\u0026#39;, path: path.resolve(__dirname, \u0026#39;dist\u0026#39;), // Needed to compile multiline strings in Cesium sourcePrefix: \u0026#39;\u0026#39; }, amd: { // Enable webpack-friendly use of require in Cesium toUrlUndefined: true }, node: { // Resolve node module use of fs fs: \u0026#39;empty\u0026#39; }, output.sourcePrefix: Adds a \\t tab before each line to override the webpack default. CesiumJS has some multiline strings, so we need to override this default with an empty prefix \u0026rsquo;\u0026rsquo;. amd.toUrlUndefined: true tells CesiumJS that the AMD webpack version used to evaluate require statements does not conform to the standard toUrl function. node.fs: \u0026rsquo;empty\u0026rsquo; resolves some third-party usage issues with the fs module, which is intended for use in a Node environment, not in a browser. Add a cesium alias so we can reference it in our application code.\n1 2 3 4 5 6 resolve: { alias: { // CesiumJS module name cesium: path.resolve(__dirname, cesiumSource) } }, Manage CesiumJS static files Finally, ensure that static CesiumJS assets, widgets, and web worker files are properly served and loaded.\nAs part of the build process, use copy-webpack-plugin to copy static files to the dist directory.\n1 npm install --save-dev copy-webpack-plugin Require it at the top of the webpack.config.js file:\n1 const CopywebpackPlugin = require(\u0026#39;copy-webpack-plugin\u0026#39;); And add it to the plugins array:\n1 2 3 4 5 6 7 8 9 plugins: [ new HtmlWebpackPlugin({ template: \u0026#39;src/index.html\u0026#39; }), // Copy Cesium Assets, Widgets, and Workers to a static directory new CopywebpackPlugin([ { from: path.join(cesiumSource, cesiumWorkers), to: \u0026#39;Workers\u0026#39; } ]), new CopywebpackPlugin([ { from: path.join(cesiumSource, \u0026#39;Assets\u0026#39;), to: \u0026#39;Assets\u0026#39; } ]), new CopywebpackPlugin([ { from: path.join(cesiumSource, \u0026#39;Widgets\u0026#39;), to: \u0026#39;Widgets\u0026#39; } ]) ], This copies the Assets and Widgets directories as well as the built web worker scripts.\nIf you are using a fork of the CesiumJS repository, the Build folder will not exist. Run npm run release to generate the output folder. For more details, see the Cesium Build Guide.\nDefine an environment variable that tells CesiumJS the base URL for loading static files using the webpack DefinePlugin. The plugins array will now look like this:\n1 2 3 4 5 6 7 8 9 10 11 12 13 plugins: [ new HtmlWebpackPlugin({ template: \u0026#39;src/index.html\u0026#39; }), // Copy Cesium Assets, Widgets, and Workers to a static directory new CopywebpackPlugin([ { from: path.join(cesiumSource, cesiumWorkers), to: \u0026#39;Workers\u0026#39; } ]), new CopywebpackPlugin([ { from: path.join(cesiumSource, \u0026#39;Assets\u0026#39;), to: \u0026#39;Assets\u0026#39; } ]), new CopywebpackPlugin([ { from: path.join(cesiumSource, \u0026#39;Widgets\u0026#39;), to: \u0026#39;Widgets\u0026#39; } ]), new webpack.DefinePlugin({ // Define relative base path in cesium for loading assets CESIUM_BASE_URL: JSON.stringify(\u0026#39;\u0026#39;) }) ], Require CesiumJS modules in our app There are several ways to reference CesiumJS modules in our application. You can use CommonJS syntax or ES6 import statements.\nYou can import the entire CesiumJS library, or require only the specific modules you need. Importing individual modules will cause webpack to only compile those modules and their dependencies in the bundle, rather than the entire library.\nCommonJS style require Require all of CesiumJS:\n1 2 var Cesium = require(\u0026#39;cesium/Cesium\u0026#39;); var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); Require individual modules:\n1 2 var Color = require(\u0026#39;cesium/Core/Color\u0026#39;); var color = Color.fromRandom(); ES6 style import Import all of CesiumJS:\n1 2 import Cesium from \u0026#39;cesium/Cesium\u0026#39;; var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); Import individual modules:\n1 2 import Color from \u0026#39;cesium/core/Color\u0026#39;; var color = Color.fromRandom(); Requiring asset files The principle behind webpack is that every file is treated as a module. This makes importing assets the same as including JavaScript. We told webpack how to load each type of file using loaders in the configuration, so we just need to call require.\n1 require(\u0026#39;cesium/Widgets/widgets.css\u0026#39;); Hello World! Create a new file, src/css/main.css, to style our application:\n1 2 3 4 5 6 7 html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } Create a div for the CesiumJS Viewer in the index.html body. Replace Hello World!\nwith the following div:\n1 \u0026lt;div id=\u0026#34;cesiumContainer\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; Remove the contents of index.js and include Cesium and our CSS files:\n1 2 3 var Cesium = require(\u0026#39;cesium/Cesium\u0026#39;); require(\u0026#39;./css/main.css\u0026#39;); require(\u0026#39;cesium/Widgets/widgets.css\u0026#39;); Add a line of code to create the Viewer:\n1 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); Run the app with npm start to view the Viewer in the browser.\nCopy and paste your favorite Sandcastle example. For instance, the Particle System Fireworks example makes for a great conclusion.\nAdvanced webpack configurations webpack can further improve performance, reduce bundle size, and perform additional or complex build steps. Here, we will discuss some configuration options related to using the CesiumJS library.\nA configuration for optimizing production Cesium webpack builds can be found in the repository example webpack.release.config.js.\nCode splitting By default, webpack bundles CesiumJS in the same chunk as our application, resulting in a large file. We can split CesiumJS into its own bundle and improve our application performance using the CommonChunksPlugin. If you end up creating multiple chunks for your application, they can all reference a common cesium chunk.\nAdd the plugin to the webpack.config.js file and specify the rules for splitting CesiumJS modules:\n1 2 3 4 5 6 plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: \u0026#39;cesium\u0026#39;, minChunks: module =\u0026gt; module.context \u0026amp;\u0026amp; module.context.indexOf(\u0026#39;cesium\u0026#39;) !== -1 }) ] Enable source maps Source maps allow webpack to trace errors back to the original content. They provide more or less detailed debugging information in exchange for compilation speed. We recommend using the \u0026rsquo;eval\u0026rsquo; option.\n1 devtool: \u0026#39;eval\u0026#39; Source maps are not recommended for production builds.\nRemove pragmas Developer errors and warnings exist in the CesiumJS source code that have been removed from our minified release builds. Since there is no built-in webpack method to remove these warnings, we will use strip-pragma-loader.\nInstall the package:\n1 npm install strip-pragma-loader --save-dev In module.rules, set debug to false and include the loader:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 rules: [{ // Strip cesium pragmas test: /\\.js$/, enforce: \u0026#39;pre\u0026#39;, include: path.resolve(__dirname, cesiumSource), use: [{ loader: \u0026#39;strip-pragma-loader\u0026#39;, options: { pragmas: { debug: false } } }] }] Uglify and minify Uglifying and minifying code allows for smaller file sizes in production. For a release build, CesiumJS uglifies JavaScript files and minifies CSS files.\nUse uglifyjs-webpack-plugin to uglify the CesiumJS source code.\n1 npm install uglifyjs-webpack-plugin --save-dev Require it in the configuration file:\n1 const UglifyJsPlugin = require(\u0026#39;uglifyjs-webpack-plugin\u0026#39;); Include it in the plugins list:\n1 2 3 plugins: [ new webpack.optimize.UglifyJsPlugin() ] Use the minimize option on css-loader to optimize CSS.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module: { rules: [{ test: /\\.css$/, use: [ \u0026#39;style-loader\u0026#39;, { loader: \u0026#39;css-loader\u0026#39;, options: { // minify loaded css minimize: true } } ] }] } Resources The official cesium-webpack-example repository contains a minimal webpack configuration, the Hello World code from this tutorial, and instructions for optional code configurations.\nFor tutorials on CesiumJS features to include in a new application, see the Cesium Workshop Tutorial.\nExplore examples in [Sandcastle] and check the CesiumJS Documentation.\nTo learn more about webpack, check out the webpack concepts, or read the documentation in depth.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | Fast Access in China: http://cesium.coinidea.com/\n","date":"2019-06-02T15:25:46Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-10-cesiumjs-and-webpack/","title":"[CesiumJS] Cesium Intermediate Tutorial 10 – CesiumJS and webpack"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | Fast Access in China: http://cesium.coinidea.com/\nTo learn the basics of particle systems, see the Particle Systems Getting Started tutorial.\nWeather Setup To generate a snow effect, first add a snowflake image for each particle, and then define the particle\u0026rsquo;s movement behavior and other dynamic elements in the updateParticle function.\nThe Images Three images are used in this tutorial. The left one is the rain particle; the middle image is the snow particle; the right image is used for the fire effect.\nThe Update Function The update function is used to define particle movement, arrangement, and visualization. It modifies the particle\u0026rsquo;s color, imageSize, and particleLife. We can even modify them based on the distance to the camera (as described below), imported models, or the distance to the Earth itself.\nHere is our update function for snow:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // snow var snowGravityVector = new Cesium.Cartesian3(); var snowUpdate = function(particle, dt) { Cesium.Cartesian3.normalize(particle.position, snowGravityVector); Cesium.Cartesian3.multiplyByScalar(snowGravityVector, Cesium.Math.randomBetween(-30.0, -300.0), snowGravityVector); particle.velocity = Cesium.Cartesian3.add(particle.velocity, snowGravityVector, particle.velocity); var distance = Cesium.Cartesian3.distance(scene.camera.position, particle.position); if (distance \u0026gt; (snowRadius)) { particle.endColor.alpha = 0.0; } else { particle.endColor.alpha = snowSystem.endColor.alpha / (distance / snowRadius + 0.1); } }; The first part of the function makes the particles fall as if affected by gravity. The update function also contains a distance check so that particles fade away when they are far from the camera.\nAdditional Weather Effects Use fog and atmospheric effects to enhance the visualization and match the type of weather we are trying to replicate.\nhueShift changes the color along the color spectrum, saturationShift changes the degree to which the actual color versus black and white is needed for the visual, and brightnessShift changes how vivid the color is.\nFog density changes the opacity between the ground cover on the Earth and the fog color. The fog\u0026rsquo;s minimumBrightness is used to darken the fog.\n1 2 3 4 5 6 7 // snow scene.skyAtmosphere.hueShift = -0.8; scene.skyAtmosphere.saturationShift = -0.7; scene.skyAtmosphere.brightnessShift = -0.33; scene.fog.density = 0.001; scene.fog.minimumBrightness = 0.8; The Systems Snow The snow system uses the snowflake_particle image and uses minimumImageSize and maximumImageSize to randomly create snowflakes within that range.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var snowParticleSize = scene.drawingBufferWidth / 100.0; var snowRadius = 100000.0; var snowSystem = new Cesium.ParticleSystem({ modelMatrix : new Cesium.Matrix4.fromTranslation(scene.camera.position), minimumSpeed : -1.0, maximumSpeed : 0.0, lifetime : 15.0, emitter : new Cesium.SphereEmitter(snowRadius), startScale : 0.5, endScale : 1.0, image : \u0026#34;../../SampleData/snowflake_particle.png\u0026#34;, emissionRate : 7000.0, startColor : Cesium.Color.WHITE.withAlpha(0.0), endColor : Cesium.Color.WHITE.withAlpha(1.0), minimumImageSize : new Cartesian2(snowParticleSize, snowParticleSize), maximumImageSize : new Cartesian2(snowParticleSize * 2.0, snowParticleSize * 2.0), updateCallback : snowUpdate }); scene.primitives.add(snowSystem); Rain The rain system uses circular_particle.png for raindrops. imageSize is used to vertically stretch the image, giving the rain a slender appearance.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 rainSystem = new Cesium.ParticleSystem({ modelMatrix : new Cesium.Matrix4.fromTranslation(scene.camera.position), speed : -1.0, lifetime : 15.0, emitter : new Cesium.SphereEmitter(rainRadius), startScale : 1.0, endScale : 0.0, image : \u0026#34;../../SampleData/circular_particle.png\u0026#34;, emissionRate : 9000.0, startColor :new Cesium.Color(0.27, 0.5, 0.70, 0.0), endColor : new Cesium.Color(0.27, 0.5, 0.70, 0.98), imageSize : new Cesium.Cartesian2(rainParticleSize, rainParticleSize * 2), updateCallback : rainUpdate }); scene.primitives.add(rainSystem); The rain update function is slightly different because rain falls much faster than snow.\n1 2 3 4 5 6 7 // rain rainGravityScratch = Cesium.Cartesian3.normalize(particle.position, rainGravityScratch); rainGravityScratch = Cesium.Cartesian3.multiplyByScalar(rainGravityScratch, -1050.0, rainGravityScratch); particle.position = Cesium.Cartesian3.add(particle.position, rainGravityScratch, particle.position); To make the environment match the atmosphere of the scene, modify the atmosphere and fog to match the rain. The code below creates a dark blue sky covered in haze.\n1 2 3 4 5 6 7 // rain scene.skyAtmosphere.hueShift = -0.97; scene.skyAtmosphere.saturationShift = 0.25; scene.skyAtmosphere.brightnessShift = -0.4; scene.fog.density = 0.00025; scene.fog.minimumBrightness = 0.01; For additional help, visit the Sandcastle example for both snow and rain.\nComet and Rocket Tails Using Multiple Particle Systems To create comet and rocket tails, we need multiple particle systems. Each position on the particle ring created by this example is a completely independent particle system. This allows us to control the direction of the system\u0026rsquo;s movement more uniformly. A simple way to visualize this effect is to limit cometOptions.numberOfSystems to 2 and have cometOptions.colorOptions include only two colors, as shown in the image below.\nTo simplify different collections of systems, create arrays to carry the independent systems associated with the comet and those associated with the rocket example.\n1 2 var rocketSystems = []; var cometSystems = []; Create two different options for the objects: one for the Comet version and another for the Rocket version. This makes the initial number of systems, offset values, etc. different for the two systems, giving them different appearances.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 var cometOptions = { numberOfSystems : 100.0, iterationOffset : 0.003, cartographicStep : 0.0000001, baseRadius : 0.0005, colorOptions : [{ red : 0.6, green : 0.6, blue : 0.6, alpha : 1.0 }, { red : 0.6, green : 0.6, blue : 0.9, alpha : 0.9 }, { red : 0.5, green : 0.5, blue : 0.7, alpha : 0.5 }] }; var rocketOptions = { numberOfSystems : 50.0, iterationOffset : 0.1, cartographicStep : 0.000001, baseRadius : 0.0005, colorOptions : [{ minimumRed : 1.0, green : 0.5, minimumBlue : 0.05, alpha : 1.0 }, { red : 0.9, minimumGreen : 0.6, minimumBlue : 0.01, alpha : 1.0 }, { red : 0.8, green : 0.05, minimumBlue : 0.09, alpha : 1.0 }, { minimumRed : 1, minimumGreen : 0.05, blue : 0.09, alpha : 1.0 }] }; colorOptions is an array of colors for random visuals. Each system starts from a specific color rather than having a set color geometry, depending on the system currently being created. In the example below, i represents the current iteration number.\n1 var color = Cesium.Color.fromRandom(options.colorOptions[i % options.colorOptions.length]); Setup Use the function below as initialization for each system:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function createParticleSystems(options, systemsArray) { var length = options.numberOfSystems; for (var i = 0; i \u0026lt; length; ++i) { scratchAngleForOffset = Math.PI * 2.0 * i / options.numberOfSystems; scratchOffset.x += options.baseRadius * Math.cos(scratchAngleForOffset); scratchOffset.y += options.baseRadius * Math.sin(scratchAngleForOffset); var emitterModelMatrix = Cesium.Matrix4.fromTranslation(scratchOffset, matrix4Scratch); var color = Cesium.Color.fromRandom(options.colorOptions[i % options.colorOptions.length]); var force = forceFunction(options, i); var item = viewer.scene.primitives.add(new Cesium.ParticleSystem({ image : getImage(), startColor : color, endColor : color.withAlpha(0.0), particleLife : 3.5, speed : 0.00005, imageSize : new Cesium.Cartesian2(15.0, 15.0), emissionRate : 30.0, emitter : new Cesium.CircleEmitter(0.1), bursts : [ ], lifetime : 0.1, forces : force, modelMatrix : particlesModelMatrix, emitterModelMatrix : emitterModelMatrix })); systemsArray.push(item); } } Since both tail versions are similar, the same createParticleSystems function can be used to create either one. Pass in CometOptions or RocketOptions as the options parameter to create different effects.\nCreate the Particle Image from Scratch Instead of loading an image from a URL, the getImage function creates the image using an HTML canvas. This makes image creation more flexible.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var particleCanvas; function getImage() { if (!Cesium.defined(particleCanvas)) { particleCanvas = document.createElement(\u0026#39;canvas\u0026#39;); particleCanvas.width = 20; particleCanvas.height = 20; var context2D = particleCanvas.getContext(\u0026#39;2d\u0026#39;); context2D.beginPath(); context2D.arc(8, 8, 8, 0, Cesium.Math.TWO_PI, true); context2D.closePath(); context2D.fillStyle = \u0026#39;rgb(255, 255, 255)\u0026#39;; context2D.fill(); } return particleCanvas; } The Force Function Below is our updateCallback function:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var scratchCartesian3 = new Cesium.Cartesian3(); var scratchCartographic = new Cesium.Cartographic(); var forceFunction = function(options, iteration) { var iterationOffset = iteration; var func = function(particle) { scratchCartesian3 = Cesium.Cartesian3.normalize(particle.position, new Cesium.Cartesian3()); scratchCartesian3 = Cesium.Cartesian3.multiplyByScalar(scratchCartesian3, -1.0, scratchCartesian3); particle.position = Cesium.Cartesian3.add(particle.position, scratchCartesian3, particle.position); scratchCartographic = Cesium.Cartographic.fromCartesian(particle.position, Cesium.Ellipsoid.WGS84, scratchCartographic); var angle = Cesium.Math.PI * 2.0 * iterationOffset / options.numberOfSystems; iterationOffset += options.iterationOffset; scratchCartographic.longitude += Math.cos(angle) * options.cartographicStep; scratchCartographic.latitude += Math.sin(angle) * options.cartographicStep; particle.position = Cesium.Cartographic.toCartesian(scratchCartographic); }; return func; }; Note that forceFunction returns a function. The returned func is the actual updateCallback function. For each iteration, the update function creates a different rotation offset based on the angle and iterationOffset. A smaller iteration offset only slightly adjusts the angle, allowing the radius to steadily increase as the system continues, as shown in the comet example. A larger iteration offset changes the angle more quickly; this creates a tighter, more erratic cylindrical output, as shown in the rocket example.\nThis tutorial uses sine and cosine functions for circular effects. For other effects, try making shapes such as a Lissajous curve, Gibbs phenomenon, or square wave.\nRelative Position Use modelMatrix to position the particle system at the appropriate location behind the plane. Because these systems are vertical, we need a slight offset using the particleOffset value. As shown in the createParticleSystems function, the emitterModelMatrix offset for each system is calculated based on the iteration.\n1 2 3 4 5 6 7 8 // positioning the plane var planePosition = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 800.0); var particlesOffset = new Cesium.Cartesian3(-8.950115473940969, 34.852766731753945, -30.235411095432937); // creating the particles model matrix var transl = Cesium.Matrix4.fromTranslation(particlesOffset, new Cesium.Matrix4()); var translPosition = Cesium.Matrix4.fromTranslation(planePosition, new Cesium.Matrix4()); var particlesModelMatrix = Cesium.Matrix4.multiplyTransformation(translPosition, transl, new Cesium.Matrix4()); Resources For additional help, visit the Sandcastle example for both tails examples. More example code:\nParticle System Demo Particle System Fireworks Demo Particle System Weather Demo Particle System Tails Demo Cesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | Fast Access in China: http://cesium.coinidea.com/\n","date":"2019-06-02T12:58:56Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-9-advanced-particle-system-effects/","title":"[CesiumJS] Cesium Intermediate Tutorial 9 – Advanced Particle System Effects"},{"content":"Cesium Chinese website: http://cesiumcn.org/ | Domestic fast access: http://cesium.coinidea.com/\nWhat is a Particle System? A particle system is a graphics technique that simulates complex physical effects. Particle systems are collections of small images that, when viewed together, form a more complex \u0026ldquo;fuzzy\u0026rdquo; object such as fire, smoke, weather, or fireworks. These complex effects can be controlled by specifying the behavior of individual particles using properties such as initial position, velocity, and lifetime.\nParticle system effects are very common in movies and video games. For example, to represent damage to an aircraft, a technical artist might use a particle system to represent an explosion on the aircraft\u0026rsquo;s engine, and then render a different particle system to represent the smoke trail as the aircraft crashes.\nParticle System Basics Take a look at the code for a basic particle system below:\n1 2 3 4 5 6 7 8 9 10 11 12 var particleSystem = viewer.scene.primitives.add(new Cesium.ParticleSystem({ image : \u0026#39;../../SampleData/smoke.png\u0026#39;, imageSize : new Cesium.Cartesian2(20, 20), startScale : 1.0, endScale : 4.0, particleLife : 1.0, speed : 5.0, emitter : new Cesium.CircleEmitter(0.5), emissionRate : 5.0, modelMatrix : entity.computeModelMatrix(viewer.clock.startTime, new Cesium.Matrix4()), lifetime : 16.0 })); The code above creates a ParticleSystem, a parameterized object that controls the appearance and behavior of individual Particle objects over time. Particles are generated by a particle emitter, have a position and type, live for a certain period of time, and then die.\nSome of these properties are dynamic. Notice that instead of using the available monochrome property scale, there is a startScale and endScale. These allow you to specify that the particle size transitions between the start and end scales over the course of the particle\u0026rsquo;s lifetime. startColor and endColor work similarly.\nOther ways to affect visual output include maximum and minimum properties. For each variable with maximum and minimum inputs, the actual value of that variable on the particle will be randomly assigned between the maximum and minimum inputs and will remain static at that value throughout the particle\u0026rsquo;s lifetime. For example, using minimum speed and maximum speed as bounds for the speed randomly selected for each particle. Properties that allow changes like this include imageSize, speed, life, and particleLife.\nEmitters When a particle is born, its initial position and velocity vector are controlled by the ParticleEmitter. The emitter will generate a number of particles per second, specified by the emissionRate parameter, initialized with a random velocity based on the emitter type.\nCesium has a variety of particle emitters that you can use out of the box.\nBoxEmitter BoxEmitter initializes particles at randomly sampled positions within a box and directs them out of one of the six box faces. It accepts a Cartesian3 parameter that specifies the width, height, and depth dimensions of the box.\n1 2 3 4 5 6 7 8 9 var particleSystem = scene.primitives.add(new Cesium.ParticleSystem({ image : \u0026#39;../../SampleData/smoke.png\u0026#39;, color: Cesium.Color.MAGENTA, emissionRate: 5.0, emitter: new Cesium.BoxEmitter(new Cesium.Cartesian3(5.0, 5.0, 5.0)), imageSize : new Cesium.Cartesian2(25.0, 25.0), modelMatrix : entity.computeModelMatrix(viewer.clock.startTime, new Cesium.Matrix4()), lifetime : 16.0 })); CircleEmitter CircleEmitter initializes particles at randomly sampled positions within a circle in the direction of the emitter\u0026rsquo;s up axis. It accepts a float parameter that specifies the radius of the circle.\n1 2 3 4 5 6 7 8 9 var particleSystem = scene.primitives.add(new Cesium.ParticleSystem({ image : \u0026#39;../../SampleData/smoke.png\u0026#39;, color: Cesium.Color.MAGENTA, emissionRate: 5.0, emitter: new Cesium.CircleEmitter(5.0), imageSize : new Cesium.Cartesian2(25.0, 25.0), modelMatrix : entity.computeModelMatrix(viewer.clock.startTime, new Cesium.Matrix4()), lifetime : 16.0 })); If no emitter is specified, CircleEmitter will be used as the default emitter.\nConeEmitter ConeEmitter initializes particles at the tip of a cone and directs them away from the cone at random angles. It takes a float parameter that specifies the angle of the cone. The cone is oriented along the emitter\u0026rsquo;s up axis.\n1 2 3 4 5 6 7 8 9 var particleSystem = scene.primitives.add(new Cesium.ParticleSystem({ image : \u0026#39;../../SampleData/smoke.png\u0026#39;, color: Cesium.Color.MAGENTA, emissionRate: 5.0, emitter: new Cesium.ConeEmitter(Cesium.Math.toRadians(30.0)), imageSize : new Cesium.Cartesian2(25.0, 25.0), modelMatrix : entity.computeModelMatrix(viewer.clock.startTime, new Cesium.Matrix4()), lifetime : 16.0 })); SphereEmitter SphereEmitter initializes particles at randomly sampled positions within a sphere and directs them outward from the center of the sphere. It takes a float parameter that specifies the radius of the sphere.\n1 2 3 4 5 6 7 8 9 var particleSystem = scene.primitives.add(new Cesium.ParticleSystem({ image : \u0026#39;../../SampleData/smoke.png\u0026#39;, color: Cesium.Color.MAGENTA, emissionRate: 5.0, emitter: new Cesium.SphereEmitter(5.0), imageSize : new Cesium.Cartesian2(25.0, 25.0), modelMatrix : entity.computeModelMatrix(viewer.clock.startTime, new Cesium.Matrix4()), lifetime : 16.0 })); Configuring Particle Systems Particle Emission Rate emissionRate controls how many particles are emitted per second, which changes the density of particles in the system. Specify a set of bursts to emit particles at specified times (as shown in the animation above). This adds variety or explosiveness to the particle system.\nAdd this property to your particleSystem:\n1 2 3 4 5 bursts : [ new Cesium.ParticleBurst({time : 5.0, minimum : 300, maximum : 500}), new Cesium.ParticleBurst({time : 10.0, minimum : 50, maximum : 100}), new Cesium.ParticleBurst({time : 15.0, minimum : 200, maximum : 300}) ] At the given times, these bursts will emit between the minimum and maximum number of particles.\nLife of the Particle and Life of the System By default, the particle system will run forever. To make the particle system run for a set duration, use lifetime to specify the duration in seconds and set loop to false.\n1 2 lifetime : 16.0, loop: false Setting particleLife to 5.0 will give every particle in the system that particleLife value. To randomize the output of each particle, use the variables minimumParticleLife and maximumArticleLife.\n1 2 minimumParticleLife: 5.0, maximumParticleLife: 10.0 Styling Particles Color Particles are styled with textures specified by image and color, which can change over the particle\u0026rsquo;s lifetime to create dynamic effects. The following code makes smoke particles transition from green to white.\n1 2 startColor : Cesium.Color.LIGHTSEAGREEN.withAlpha(0.7), endColor : Cesium.Color.WHITE.withAlpha(0.0), Size The size of a particle is controlled by imageSize. To randomize the size, use minimumImageSize.x and maximumImageSize.x to control the width (in pixels), and minimumImageSize.y and maximumImageSize.y to control the height (in pixels). The following code creates square particles between 30 and 60 pixels:\n1 2 minimumImageSize : new Cesium.Cartesian2(30.0, 30.0), maximumImageSize : new Cesium.Cartesian2(60.0, 60.0) The size of particles can be adjusted over their lifetime using the startScale and endScale properties to make particles grow or shrink over time.\n1 2 startScale: 1.0, endScale: 4.0 Speed Speed is controlled by speed or minimumSpeed and maximumSpeed.\n1 2 minimumSpeed: 5.0, maximumSpeed: 10.0 UpdateCallback Particle systems can be further customized by applying an update function. It acts as a manual updater for each particle for effects such as gravity, wind, or color changes.\nThe particle system has an updateCallback that modifies particle properties during the simulation. This function takes the particle and the simulation time step. Most physics-based effects will modify the velocity vector to change direction or speed. Here is an example that makes particles react to gravity:\n1 2 3 4 5 6 7 8 9 10 11 var gravityVector = new Cesium.Cartesian3(); var gravity = -(9.8 * 9.8); function applyGravity(p, dt) { // Compute a local up vector for each particle in geocentric space. var position = p.position; Cesium.Cartesian3.normalize(position, gravityVector); Cesium.Cartesian3.multiplyByScalar(gravityVector, gravity * dt, gravityVector); p.velocity = Cesium.Cartesian3.add(p.velocity, gravityVector, p.velocity); } This function computes the gravity vector and uses gravitational acceleration to change the particle\u0026rsquo;s velocity. Set gravity as the updateFunction of the particle system:\n1 updateCallback : applyGravity Positioning Particle systems are positioned using two Matrix4 transformation matrices:\nmodelMatrix: Transforms the particle system from model to world coordinates. emitterModelMatrix: Transforms the particle system emitter within the particle system\u0026rsquo;s local coordinate system. You can use just one of these transformation matrices and leave the other as the identity matrix, but we provide both for convenience. To practice creating matrices, let\u0026rsquo;s position the particle emitter relative to another entity.\nCreate an entity for our particle system. Open the Hello World Sandcastle example and add the following code to add a milk truck model to the viewer:\n1 2 3 4 5 6 7 var entity = viewer.entities.add({ model : { uri : \u0026#39;../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck-kmc.glb\u0026#39; }, position : Cesium.Cartesian3.fromDegrees(-75.15787310614596, 39.97862668312678) }); viewer.trackedEntity = entity; We want to add a smoke effect coming from the back of the truck. Create a model matrix that will position the particle system and orient it the same as the milk truck entity.\n1 modelMatrix: entity.computeModelMatrix(time, new Cesium.Matrix4()) This places the particle system at the center of the truck. To position it at the back of the truck, we can create a matrix with a translation.\n1 2 3 4 5 6 7 function computeEmitterModelMatrix() { hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr); trs.translation = Cesium.Cartesian3.fromElements(-4.0, 0.0, 1.4, translation); trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation); return Cesium.Matrix4.fromTranslationRotationScale(trs, emitterModelMatrix); } Now, add the particle system:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var particleSystem = viewer.scene.primitives.add(new Cesium.ParticleSystem({ image : \u0026#39;../../SampleData/smoke.png\u0026#39;, startColor : Cesium.Color.LIGHTSEAGREEN.withAlpha(0.7), endColor : Cesium.Color.WHITE.withAlpha(0.0), startScale : 1.0, endScale : 4.0, particleLife : 1.0, minimumSpeed : 1.0, maximumSpeed : 4.0 imageSize : new Cesium.Cartesian2(25, 25), emissionRate : 5.0, lifetime : 16.0, modelMatrix : entity.computeModelMatrix(viewer.clock.startTime, new Cesium.Matrix4()) emitterModelMatrix : computeEmitterModelMatrix() })); Also note that we can update the model or emitter matrices over time. For example, if we want to animate the emitter position on the truck, we can modify the emitterModelMatrix while keeping the modelMatrix unchanged.\nTo see the complete example, visit the Particle System demo.\nLearn More For achieving cooler effects with particle systems using more advanced techniques, see the Particle Systems - More Effects tutorial. For more example code, see:\nParticle System Fireworks Demo Particle Systems Weather Particle Systems Tails Cesium Chinese website QQ group: 807482793\nCesium Chinese website: http://cesiumcn.org/ | Domestic fast access: http://cesium.coinidea.com/\n","date":"2019-06-02T09:41:38Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-8-introduction-to-particle-systems/","title":"[CesiumJS] Cesium Intermediate Tutorial 8 – Introduction to Particle Systems"},{"content":"Cesium Chinese website: http://cesiumcn.org/ | Fast access in China: http://cesium.coinidea.com/\nThis tutorial will introduce you to the geometry and appearance system using the Primitive API. This is an advanced topic for extending CesiumJS with custom meshes, shapes, volumes, and appearances, rather than for general Cesium users. If you are interested in learning how to draw various shapes and volumes on the globe, please check out the Creating Entities tutorial. CesiumJS can create different geometry types using entities (such as polygons and ellipsoids). For example, copy and paste the following code into the Hello World Sandcastle example to create a rectangle with a stripe pattern on the globe:\n1 2 3 4 5 6 7 8 9 10 11 12 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); viewer.entities.add({ rectangle : { coordinates : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), material : new Cesium.StripeMaterialProperty({ evenColor: Cesium.Color.WHITE, oddColor: Cesium.Color.BLUE, repeat: 5 }) } }); In this tutorial, we will go under the hood and look at the geometry and appearance types that make them up. Geometry defines the structure of a Primitive, i.e., the triangles, lines, or points that make up the primitive. Appearance defines the shading of the Primitive, including its full GLSL vertex and fragment shaders, as well as the render state.\nThe benefits of using geometry and appearances are:\nPerformance: When drawing a large number of Primitives (such as polygons for every zip code in the United States), using geometry directly allows us to combine them into a single geometry to reduce CPU overhead and better utilize the GPU. Combining Primitives is done on a web worker to keep the UI responsive. Flexibility: Primitives combine geometry and appearance. By separating them, we can modify each independently. We can add new geometries that are compatible with many different appearances, and vice versa. Low-level access: Appearances provide close-to-the-metal rendering access without worrying about all the details of using the Renderer directly. Appearances make it easy to: Write full GLSL vertex and fragment shaders Use custom render states Of course, there are also some drawbacks:\nUsing geometry and appearances directly requires more code and a deeper understanding of graphics. Entities are at an abstraction level suitable for mapping applications; geometry and appearances are at an abstraction level closer to a traditional 3D engine. Combining geometries is effective for static data, but not necessarily for dynamic data. Let\u0026rsquo;s rewrite the initial code example using geometry and appearances:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; // original code //viewer.entities.add({ // rectangle : { // coordinates : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), // material : new Cesium.StripeMaterialProperty({ // evenColor: Cesium.Color.WHITE, // oddColor: Cesium.Color.BLUE, // repeat: 5 // }) // } //}); var instance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT }) }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : instance, appearance : new Cesium.EllipsoidSurfaceAppearance({ material : Cesium.Material.fromType(\u0026#39;Stripe\u0026#39;) }) })); We used a Primitive (Primitive) instead of a rectangle entity, which combines geometry and appearance. For now, we will not distinguish between Geometry and GeometryInstance. An instance is not just an instance of a geometry, but also a container for it.\nTo create the geometry for a rectangle \u0026ndash; the triangles covering the rectangular area and conforming to the curvature of the globe \u0026ndash; we created a RectangleGeometry.\nSince it is on the surface, we can use EllipsoidSurfaceAppearance. This saves memory by assuming the geometry is on the surface or at a constant height above the ellipsoid.\nGeometry Types CesiumJS provides the following geometries:\nCombining Geometry When we use a single Primitive to draw multiple static geometries, we see performance benefits. For example, drawing two rectangles in one Primitive.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; var instance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT }) }); var anotherInstance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0), vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT }) }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : [instance, anotherInstance], appearance : new Cesium.EllipsoidSurfaceAppearance({ material : Cesium.Material.fromType(\u0026#39;Stripe\u0026#39;) }) })); We created another instance with a different rectangle, then provided both instances to the Primitive. This draws both instances with the same appearance.\nSome appearances allow each instance to provide unique attributes. For example, we can use PerInstanceColorAppearance to shade each instance with a different color.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; var instance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), attributes : { color : new Cesium.ColorGeometryInstanceAttribute(0.0, 0.0, 1.0, 0.8) } }); var anotherInstance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0), vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), attributes : { color : new Cesium.ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 0.8) } }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : [instance, anotherInstance], appearance : new Cesium.PerInstanceColorAppearance() })); Each instance has a color attribute. The Primitive is constructed with PerInstanceColorAppearance, which uses each instance\u0026rsquo;s color attribute to determine the shading.\nCombining geometries allows CesiumJS to efficiently draw many geometries. The following example draws 2,592 uniquely colored rectangles.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; var instances = []; for (var lon = -180.0; lon \u0026lt; 180.0; lon += 5.0) { for (var lat = -85.0; lat \u0026lt; 85.0; lat += 5.0) { instances.push(new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(lon, lat, lon + 5.0, lat + 5.0), vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({alpha : 0.5})) } })); } } scene.primitives.add(new Cesium.Primitive({ geometryInstances : instances, appearance : new Cesium.PerInstanceColorAppearance() })); Picking Instances can be accessed independently after being combined. Assign an ID to an instance and use it to determine whether that instance is picked using Scene.Pick.\nThe following example creates an instance with an id and writes a message to the console when the instance is clicked.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; var instance = new Cesium.GeometryInstance({ geometry : new Cesium.RectangleGeometry({ rectangle : Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0), vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), id : \u0026#39;my rectangle\u0026#39;, attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED) } }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : instance, appearance : new Cesium.PerInstanceColorAppearance() })); var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); handler.setInputAction(function (movement) { var pick = scene.pick(movement.position); if (Cesium.defined(pick) \u0026amp;\u0026amp; (pick.id === \u0026#39;my rectangle\u0026#39;)) { console.log(\u0026#39;Mouse clicked rectangle.\u0026#39;); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); Using id avoids keeping a reference to the entire instance in memory after the Primitive is constructed, including the geometry.\nGeometry Instances Instances can be used to position, scale, and rotate the same geometry in different parts of the scene. This is possible because multiple instances can reference the same Geometry, and each instance can have a different modelMatrix. This allows us to compute the geometry only once and reuse it multiple times.\nThe following example creates an EllipsoidGeometry and two instances. Each instance references the same ellipsoid geometry but uses a different modelMatrix to place it, resulting in one ellipsoid positioned above the other.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; var ellipsoidGeometry = new Cesium.EllipsoidGeometry({ vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT, radii : new Cesium.Cartesian3(300000.0, 200000.0, 150000.0) }); var cyanEllipsoidInstance = new Cesium.GeometryInstance({ geometry : ellipsoidGeometry, modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-100.0, 40.0)), new Cesium.Cartesian3(0.0, 0.0, 150000.0), new Cesium.Matrix4() ), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.CYAN) } }); var orangeEllipsoidInstance = new Cesium.GeometryInstance({ geometry : ellipsoidGeometry, modelMatrix : Cesium.Matrix4.multiplyByTranslation( Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-100.0, 40.0)), new Cesium.Cartesian3(0.0, 0.0, 450000.0), new Cesium.Matrix4() ), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.ORANGE) } }); scene.primitives.add(new Cesium.Primitive({ geometryInstances : [cyanEllipsoidInstance, orangeEllipsoidInstance], appearance : new Cesium.PerInstanceColorAppearance({ translucent : false, closed : true }) })); Updating Per-Instance Attributes After geometry is added to a Primitive, update per-instance attributes of the geometry to change the visualization. Per-instance attributes include:\nColor: ColorGeometryInstanceAttribute determines the color of the instance. The Primitive must have a PerInstanceColorAppearance. Show: A boolean type that determines whether the instance is visible. All instances have this attribute. The following demonstrates how to change the color of a geometry instance:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; var circleInstance = new Cesium.GeometryInstance({ geometry : new Cesium.CircleGeometry({ center : Cesium.Cartesian3.fromDegrees(-95.0, 43.0), radius : 250000.0, vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT }), attributes : { color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 0.0, 0.0, 0.5)) }, id: \u0026#39;circle\u0026#39; }); var primitive = new Cesium.Primitive({ geometryInstances : circleInstance, appearance : new Cesium.PerInstanceColorAppearance({ translucent : false, closed : true }) }); scene.primitives.add(primitive); setInterval(function() { var attributes = primitive.getGeometryInstanceAttributes(\u0026#39;circle\u0026#39;); attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({alpha : 1.0})); },2000); The attributes of a geometry instance can be retrieved from the primitive using primitive.getGeometryInstanceAttributes. The properties of attributes can be changed directly.\nAppearances Geometry defines the structure. The other key property of a primitive, appearance, defines the shading of the primitive, i.e., the color of individual pixels. A primitive can have multiple geometry instances but only one appearance. Depending on the type of appearance, the appearance will have a material that defines the body of the shading.\nCesiumJS has the following appearances:\nAppearances define the full GLSL vertex and fragment shaders that are executed on the GPU when drawing a Primitive. Appearances also define the full render state, which controls the state of the GPU when drawing a primitive. We can define the render state directly, or use higher-level properties like \u0026ldquo;closed\u0026rdquo; and \u0026ldquo;translucent\u0026rdquo;, which the appearance will convert into render state. For example:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // Perhaps for an opaque box that the viewer will not enter. // - Backface culled and depth tested. No blending. var appearance = new Cesium.PerInstanceColorAppearance({ translucent : false, closed : true }); // This appearance is the same as above var anotherAppearance = new Cesium.PerInstanceColorAppearance({ renderState : { depthTest : { enabled : true }, cull : { enabled : true, face : Cesium.CullFace.BACK } } }); Once an appearance is created, its renderState property cannot be changed, but its material can. We can also change the appearance property of a primitive.\nMost appearances also have flat and faceForward properties, which indirectly control the GLSL shaders.\nflat: Flat shading. Do not consider lighting. faceForward: When lighting, flip the normal so that it always faces the viewer. Avoids dark areas on the back side, such as the inside of a wall. Geometry and Appearance Compatibility Not all appearances work with all geometries. For example, the EllipsoidSurfaceAppearance does not work with WallGeometry because a wall is not on the surface of the globe.\nFor an appearance to be compatible with a geometry, they must have matching vertex formats, meaning the geometry must have the input data expected by the appearance. A vertexFormat can be provided when creating a geometry.\nThe vertexFormat of a geometry determines whether it can be combined with other geometries. Two geometries do not need to be the same type, but they need matching vertex formats.\nFor convenience, appearances either have a vertexFormat property or a VERTEX_FORMAT static constant that can be passed as a geometry option.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var geometry = new Ceisum.RectangleGeometry({ vertexFormat : Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT // ... }); var geometry2 = new Ceisum.RectangleGeometry({ vertexFormat : Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT // ... }); var appearance = new Ceisum.MaterialAppearance(/* ... */); var geometry3 = new Ceisum.RectangleGeometry({ vertexFormat : appearance.vertexFormat // ... }); Resources Reference documentation:\nAll geometries All appearances Primitive GeometryInstance For more materials, visit: Fabric For future plans, visit: Geometry and Appearances Roadmap\nCesium Chinese website QQ group: 807482793\nCesium Chinese website: http://cesiumcn.org/ | Fast access in China: http://cesium.coinidea.com/\n","date":"2019-06-02T08:00:38Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-7-geometry-and-appearances/","title":"[CesiumJS] Cesium Intermediate Tutorial 7 – Geometry and Appearances"},{"content":"Cesium Chinese website: http://cesiumcn.org/ | Fast domestic access: http://cesium.coinidea.com/\nThis tutorial will teach you how to convert, load, and use 3D models in Cesium through the Primitive API. If you are new to Cesium, you may want to read the 3D models section of the Spatial Data Visualization Tutorial, referred to as \u0026ldquo;Spatial Data Visualization\u0026rdquo; in this tutorial series.\nCesium supports 3D models, including keyframe animations, skinning, and individual node picking, using glTF — an emerging industry-standard format developed by the Khronos Group (the consortium behind WebGL and COLLADA) for 3D models on the web. Cesium also provides a web-based tool to convert COLLADA models to glTF for optimized use with Cesium.\nQuick Start Cesium includes several ready-to-use binary glTF models:\nAn airplane with animated propellers A ground vehicle with animated wheels A character with skinned walk cycle A hot air balloon A milk truck (also available in Draco-compressed format) These models each have their own directory in Apps/SampleData/models. Most will include the original COLLADA file (.dae), glTF file (.gltf), and/or binary glTF file (.glb). The original COLLADA file is not needed for use in a Cesium application.\nLet\u0026rsquo;s write code to load these models. Open Sandcastle\u0026rsquo;s Hello World example. Below line 4 var viewer=\u0026hellip;, add a scene variable.\n1 var scene = viewer.scene; Next, load the ground vehicle model using Cesium.Model from glTF by adding the following code.\n1 2 3 4 5 6 7 var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( Cesium.Cartesian3.fromDegrees(-75.62898254394531, 40.02804946899414, 0.0)); var model = scene.primitives.add(Cesium.Model.fromGltf({ url : \u0026#39;../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb\u0026#39;, modelMatrix : modelMatrix, scale : 200.0 })); Press F8, then use the geocoder tool in the upper right corner to zoom to Exton, PA.\nWe are now looking directly at the ground vehicle. We can right-click drag to zoom in, and middle-click drag to tilt the view.\nCesium.Model.fromGltf asynchronously loads a glTF model, including any external files, and renders the model once it is fully loaded, resolving the readyPromise. Only the URL of the .gltf file is required, which in this case is ../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb.\nscale is provided as an optional parameter to fromGltf to enlarge the model. Many real-sized models can also appear very small. So using a larger scale value for the first test of a model is helpful, such as 200000.0, as shown below:\nmodelMatrix is also provided to fromGltf to position and rotate the model. This creates a local coordinate system for the model. Here, Cesium.Transforms.eastNorthUpToFixedFrame is used to create a local East-North-Up coordinate system with its origin at longitude -75.62898254394531 degrees, latitude 40.02804946899414 degrees. The model\u0026rsquo;s modelMatrix property can be changed at any time to move the model.\nTo visualize the coordinate system, use the Cesium Inspector by adding the following code anywhere below line 4 var viewer=\u0026hellip;:\n1 viewer.extend(Cesium.viewerCesiumInspectorMixin); Press F8, and the inspector interface will appear in the upper left. Expand Primitives, click Pick a Primitive, click on the ground vehicle model, and then check show reference frame.\nHere: the x-axis (East) is red, the y-axis (North) is green, and the z-axis (Up) is blue.\nWe can use the same code to load the airplane or character model by simply changing the URL passed to fromGltf to \u0026ldquo;../../../../Apps/SampleData/models/CesiumAir/Cesium-Air.glb\u0026rdquo; or \u0026ldquo;../../../../Apps/SampleData/models/CesiumMan/Cesium-Man.glb\u0026rdquo;. See the reference documentation for Cesium.Model.fromGltf for all available options.\nAnimations Each of these models has built-in animations created by an artist (for example, an artist defines several key poses to create an animation), and Cesium interpolates them at runtime to create smooth animations.\nTo play animations, add the following code after the call to Cesium.Model.fromGltf.\n1 2 3 4 5 Cesium.when(model.readyPromise).then(function(model) { model.activeAnimations.addAll({ loop : Cesium.ModelAnimationLoop.REPEAT }); }); Since animations are stored in the glTF model, we need to wait for the readyPromise to resolve before accessing them. addAll is used to play all animations in the model. Cesium.ModelAnimationLoop.REPEAT loops the animation until it is removed from the activeAnimations collection. To play a specific animation, use add instead, providing the animation\u0026rsquo;s id (the glTF JSON property name).\nIn addition to the loop option, addAll and add provide many options to control the animation\u0026rsquo;s start and stop time, speed, and direction. For example, the following animation runs at half speed (relative to the Cesium clock) and in reverse.\n1 2 3 4 5 model.activeAnimations.addAll({ loop : Cesium.ModelAnimationLoop.REPEAT, speedup : 0.5, reverse : true }); add returns a ModelAnimation object (addAll returns an array of these objects) that includes events for when the animation starts, stops, and updates each frame. For example, this allows starting one animation relative to another. See the API documentation for start, stop, and update events.\nAnimations are synchronized with the Cesium clock, so to see them, press play on the play widget. You can use the timeline and play widget to increase, decrease, and reverse the animation speed.\nTo configure the application to automatically play animations, initialize the viewer as follows:\n1 2 3 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;, { shouldAnimate : true }); Picking As with all Cesium primitives, Scene.pick will return a model as part of its result if one is picked. Additionally, the ids (JSON property names) of the glTF node and glTF mesh are returned, enabling precise picking of different model parts. The following example displays the node and mesh names under the mouse cursor in the console window.\n1 2 3 4 5 6 7 8 9 10 var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); handler.setInputAction( function (movement) { var pick = scene.pick(movement.endPosition); if (Cesium.defined(pick) \u0026amp;\u0026amp; Cesium.defined(pick.node) \u0026amp;\u0026amp; Cesium.defined(pick.mesh)) { console.log(\u0026#39;node: \u0026#39; + pick.node.name + \u0026#39;. mesh: \u0026#39; + pick.mesh.name); } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE ); Converting COLLADA to glTF To fully convert COLLADA models to glTF format for use with Cesium, you can use the web-based COLLADA-to-glTF converter. This tool can convert .dae files and image files into a .gltf file with embedded images.\nTroubleshooting If you encounter problems loading a 3D model in Cesium, first determine where the problem lies. The issue may be in:\nThe modeling tool\u0026rsquo;s exporter, such as Maya, Modo, SketchUp, etc. The COLLADA-to-glTF conversion tool The Cesium glTF renderer Troubleshooting on Mac On Mac, to determine whether a COLLADA file was exported correctly, double-click the .dae file, which should display in the Preview window. If the model has animations, hovering over the bottom of the window will reveal a toolbar to play them.\nIf the COLLADA file is invalid, Preview will display an error. This usually indicates a bug in the COLLADA exporter used to create the COLLADA file.\nTo troubleshoot this, install Xcode, then right-click the .dae file and select Open With -\u0026gt; Xcode.\nXcode displays the model similarly to Preview but with more features, such as the ability to select individual nodes. Xcode also implements many workarounds for invalid COLLADA files, so it can often load and preview COLLADA files that Preview cannot. If the model loads in Xcode, select File -\u0026gt; Save to save the model with the workarounds applied, and it should then load in Preview.\nIf it still doesn\u0026rsquo;t load in Preview, then there is an issue with the COLLADA exporter. Make sure you have the latest version of the modeling tool, and try the tips in this article. If it still doesn\u0026rsquo;t work, file a bug with the modeling tool (not Cesium). It\u0026rsquo;s also worth trying to export as .fbx or another format, then importing into another modeling tool with a better COLLADA exporter.\nTroubleshooting on Windows On Windows, Visual Studio 2013 includes a model editor in the free Community Edition that can load COLLADA models. To determine whether the COLLADA file was exported correctly, drag the .dae file into Visual Studio and it should load. If it doesn\u0026rsquo;t load, this usually indicates a bug in the COLLADA exporter. Make sure you have the latest version of the modeling tool, and try the tips in this article. If it still doesn\u0026rsquo;t work, file a bug with the modeling tool (not Cesium). It\u0026rsquo;s also worth trying to export as .fbx or another format, then importing into another modeling tool with a better COLLADA exporter.\nIf you don\u0026rsquo;t have Visual Studio, Autodesk has a WebGL viewer that allows drag and drop and doesn\u0026rsquo;t require login. The viewer does not support animations. If the model has images, upload a zip package containing the .dae and image files.\nTroubleshooting in Cesium Once we have a valid COLLADA file, run it through the COLLADA-to-glTF converter, then try loading it into Cesium. If it doesn\u0026rsquo;t load into Cesium or displays incorrectly, there is a bug in either the converter or Cesium. To get more details, open the browser\u0026rsquo;s developer tools (Ctrl-Shift-I in Chrome) and enable Pause on all exceptions (in Chrome\u0026rsquo;s Sources tab), then reload the Cesium application.\nPost a message to the Cesium Forum, and we can usually provide a workaround until a fix is available. In your post, please include:\nThe original COLLADA and converted glTF files. We understand that not everyone can share their models, but if you can, it greatly improves our ability to help. The browser\u0026rsquo;s console window and any exceptions thrown when loading the model, for example: Resources Check out the 3D Models example in Sandcastle and the reference documentation for Model and ModelAnimationCollection.\nCesium Chinese community QQ group: 807482793\nCesium Chinese website: http://cesiumcn.org/ | Fast domestic access: http://cesium.coinidea.com/\n","date":"2019-05-23T13:08:49Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-6-3d-models/","title":"[CesiumJS] Cesium Intermediate Tutorial 6 – 3D Models"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCesiumJS supports streaming and visualizing high-resolution terrain along with water-related effects for oceans, lakes, and rivers. View mountain peaks, valleys, and other terrain features while embracing the 3D digital globe. Stream your own tiled terrain data or high-resolution managed terrain such as Cesium World Terrain using Cesium ion.\nQuick Start Open the Sandcastle Hello World example. By default, the globe is a WGS84 ellipsoid. Specify a different terrain provider by passing the terrainProvider option to Viewer. Let\u0026rsquo;s use Cesium World Terrain:\n1 2 3 4 Cesium.Ion.defaultAccessToken = \u0026#39;your_access_token\u0026#39;; var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;, { terrainProvider : Cesium.createWorldTerrain() }); NOTE: Create a Cesium account. This tutorial uses terrain provided by Cesium ion. Create an account to obtain an access token for using terrain in this tutorial. Sign up here. The example code above will automatically update with your token. If you already have an account, sign in.\nAfter modifying the example, press F8 to run it. Zoom to a mountainous area, hold the middle mouse button and drag to tilt to a horizon view. Here is what Mount Everest looks like:\nAs we zoom closer, CesiumJS fetches higher resolution terrain based on which parts of the globe are visible and how far away they are.\nTerrain and imagery are handled separately, and any imagery provider can be used with any terrain provider. See the Imagery Layers Tutorial for managing imagery.\nEnabling Terrain Lighting and Water Effects Cesium World Terrain also includes terrain lighting data and coastline data needed for water effects. By default, this data is not sent along with terrain tiles. To enable terrain lighting, set requestVertexNormals to true and turn on global lighting.\n1 2 3 4 5 6 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;, { terrainProvider : Cesium.createWorldTerrain({ requestVertexNormals: true }) }); viewer.scene.globe.enableLighting = true; Below is the same view of Mount Everest with terrain lighting enabled based on sun position.\nEnable water effects in a similar way using requestWaterMask:\n1 2 3 4 5 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;, { terrainProvider : Cesium.createWorldTerrain({ requestWaterMask: true }) }); Zoom to an area with water to see the effect. Here is the San Francisco Bay:\nOver time, waves ripple and bright specular reflections from the sun and moon appear. Customize the water effect using Globe.oceanNormalMapUrl for wave creation. Changing the imagery provider also affects the appearance of the water, as the water color blends with the underlying imagery.\nSee the Sandcastle Terrain example to explore some interesting terrain and water effect areas.\nTerrain Ready for Streaming Cesium World Terrain: High-resolution world terrain with extended support for terrain lighting and water effects. Cesium World Terrain supports online access via Cesium ion and paid downloads for offline access. Adding it to your Cesium application will quickly improve terrain visualization. Cesium World Terrain is also available via on-premise deployment.\nTerrain Providers Cesium supports several methods for requesting terrain based on terrain providers. Most terrain providers use REST interfaces over HTTP to request terrain tiles. Terrain providers differ based on the format of the request and how the terrain data is organized. CesiumJS supports the following terrain providers:\nCesiumTerrainProvider: Supports quantized-mesh terrain tiles optimized for terrain streaming. Compatible with terrain served by Cesium ion and output from the 3D tiling pipeline. GoogleEarthEnterpriseTerrainProvider: Supports heightmap terrain generated by your Google Earth Enterprise server. VRTheWorldTerrainProvider: Supports heightmap terrain requested from VT MAK VR-TheWorld Server. EllipsoidTerrainProvider: Procedurally creates the surface of an ellipsoid. Lacks realistic terrain appearance but does not request data from a server. Terrain provider construction is similar to imagery providers and typically includes the terrain server URL and an optional proxy if the server does not support Cross-Origin Resource Sharing (CORS).\nResources View the Terrain example in Sandcastle and reference documentation for all terrain providers.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2019-05-22T09:33:44Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-5-terrain/","title":"[CesiumJS] Cesium Intermediate Tutorial 5 - Terrain"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nEntity Features in Viewer Let\u0026rsquo;s look at the functions that Viewer provides for manipulating entities.\nSelection and Description Clicking an entity in the Viewer will display a SelectionIndicator widget at the entity\u0026rsquo;s location, providing an InfoBox for presenting more information. We can set name to define the title of the InfoBox. We can also provide the Entity.description property in HTML format.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 wyoming.name = \u0026#39;wyoming\u0026#39;; wyoming.description = \u0026#39;\\ \u0026lt;img\\ width=\u0026#34;50%\u0026#34;\\ style=\u0026#34;float:left; margin: 0 1em 1em 0;\u0026#34;\\ src=\u0026#34;//cesium.com/docs/tutorials/creating-entities/Flag_of_Wyoming.svg\u0026#34;/\u0026gt;\\ \u0026lt;p\u0026gt;\\ Wyoming is a state in the mountain region of the Western \\ United States.\\ \u0026lt;/p\u0026gt;\\ \u0026lt;p\u0026gt;\\ Wyoming is the 10th most extensive, but the least populous \\ and the second least densely populated of the 50 United \\ States. The western two thirds of the state is covered mostly \\ with the mountain ranges and rangelands in the foothills of \\ the eastern Rocky Mountains, while the eastern third of the \\ state is high elevation prairie known as the High Plains. \\ Cheyenne is the capital and the most populous city in Wyoming, \\ with a population estimate of 63,624 in 2017.\\ \u0026lt;/p\u0026gt;\\ \u0026lt;p\u0026gt;\\ Source: \\ \u0026lt;a style=\u0026#34;color: WHITE\u0026#34;\\ target=\u0026#34;_blank\u0026#34;\\ href=\u0026#34;http://en.wikipedia.org/wiki/Wyoming\u0026#34;\u0026gt;Wikipedia\u0026lt;/a\u0026gt;\\ \u0026lt;/p\u0026gt;\u0026#39;; All HTML displayed in the InfoBox is sandboxed. This prevents external data sources from injecting malicious content into the Cesium application. To run JavaScript or browser plugins within the description, access the sandboxed iframe via the viewer.infoBox.frame property. Refer to this article for more information on controlling iframe sandboxing.\nCamera Controls Use the viewer.zoomTo command to view a specific Entity. There is also a viewer.flyTo method for performing animated Camera flights to an Entity. Both methods can be passed an Entity, EntityCollection, DataSource, or an array of entities.\nEither method will calculate the view for all provided entities. By default, the Camera faces north and looks down at a 45-degree angle. Customize this by passing in a HeadingPitchRange.\n1 2 3 var heading = Cesium.Math.toRadians(90); var pitch = Cesium.Math.toRadians(-30); viewer.zoomTo(wyoming, new Cesium.HeadingPitchRange(heading, pitch)); zoomTo and flyTo are both asynchronous functions; that is, they are not guaranteed to complete before returning. For example, flying to an Entity happens over many animation frames. Both functions return Promises that can be used to schedule actions to perform after the flight or zoom completes. Replace zoomTo in the example with the following code snippet. This flies to Wyoming and selects it after the flight ends.\n1 2 3 4 5 viewer.flyTo(wyoming).then(function(result){ if (result) { viewer.selectedEntity = wyoming; } }); The result parameter passed to the callback function will be true if the flight completed successfully; false if the flight was cancelled \u0026ndash; that is, the user initiated another flight or zoom before this one completed; or if the target had no corresponding visualization, i.e., nothing to zoom to.\nSometimes, especially when working with time-dynamic data, we want the Camera to focus on and follow an entity rather than the center of the Earth. This can be accomplished by setting viewer.trackedEntity. Tracking an entity requires setting a position.\n1 2 wyoming.position = Cesium.Cartesian3.fromDegrees(-107.724, 42.68); viewer.trackedEntity = wyoming; To stop tracking, set viewer.trackedEntity to undefined or double-click away from the entity. Calling zoomTo or flyTo will also cancel tracking.\nManaging Entities EntityCollection is an associative array for managing and monitoring a group of entities. viewer.entities is an EntityCollection. EntityCollection includes methods for managing entities such as add, remove, and removeAll.\nSometimes we need to update entities we previously created. All entity instances have a unique id that can be used to retrieve entities from the collection. We can assign an ID to an entity, otherwise one will be automatically generated.\n1 2 3 viewer.entities.add({ id : \u0026#39;uniqueId\u0026#39; }); Use getById to retrieve an entity. If no entity with the provided ID exists, undefined is returned.\n1 var entity = viewer.entities.getById(\u0026#39;uniqueId\u0026#39;); To get an entity or create a new one if it doesn\u0026rsquo;t exist, use getOrCreateEntity.\n1 var entity = viewer.entities.getOrCreateEntity(\u0026#39;uniqueId\u0026#39;); Manually create a new entity and use add to add it to the collection. This method will throw an exception if an entity with the same id already exists in the collection.\n1 2 3 4 var entity = new Entity({ id: \u0026#39;uniqueId\u0026#39; }); viewer.entities.add(entity); EntityCollection emits events using the CollectionChanged event. Listeners are notified when entities are added, removed, or updated in the collection.\nUse the [Geometry Showcase] (https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/index.html?src=Geometry and Appearances.html\u0026amp;label=Showcases) example in Sandcastle. Paste the following code after the line that creates the viewer.\n1 2 3 4 5 6 7 8 function onChanged(collection, added, removed, changed){ var msg = \u0026#39;Added ids\u0026#39;; for(var i = 0; i \u0026lt; added.length; i++) { msg += \u0026#39;\\n\u0026#39; + added[i].id; } console.log(msg); } viewer.entities.collectionChanged.addEventListener(onChanged); When running the example, you should see about 65 messages in the console, one for each call to viewer.entities.add.\nWhen updating a large number of entities at once, it is more performant to queue the updates and send a single event at the end. This allows Cesium to process the required changes in a single pass. At the end of the example, call viewer.entities.suspendEvents before viewer.entities.add, and call viewer.entities.resumeEvents after. When running the demo again, we now get a single event containing all 65 entities. These calls are reference-counted, so multiple suspend and resume calls can be nested.\nPicking Picking (clicking to select an object) is an area where we need brief interaction with the base API. Use scene.pick and scene.drillPick to retrieve entities.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 /** * Returns the top-most entity at the provided window coordinates * or undefined if no entity is at that location. * * @param {Cartesian2} windowPosition The window coordinates. * @returns {Entity} The picked entity or undefined. */ function pickEntity(viewer, windowPosition) { var picked = viewer.scene.pick(windowPosition); if (defined(picked)) { var id = Cesium.defaultValue(picked.id, picked.primitive.id); if (id instanceof Cesium.Entity) { return id; } } return undefined; }; /** * Returns the list of entities at the provided window coordinates. * The entities are sorted front to back by their visual order. * * @param {Cartesian2} windowPosition The window coordinates. * @returns {Entity[]} The picked entities or undefined. */ function drillPickEntities(viewer, windowPosition) { var i; var entity; var picked; var pickedPrimitives = viewer.scene.drillPick(windowPosition); var length = pickedPrimitives.length; var result = []; var hash = {}; for (i = 0; i \u0026lt; length; i++) { picked = pickedPrimitives[i]; entity = Cesium.defaultValue(picked.id, picked.primitive.id); if (entity instanceof Cesium.Entity \u0026amp;\u0026amp; !Cesium.defined(hash[entity.id])) { result.push(entity); hash[entity.id] = true; } } return result; }; Points, Billboards, and Labels Create graphical points or labels by setting position, point, and label. For example, place a point at our favorite sports team\u0026rsquo;s home stadium.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var citizensBankPark = viewer.entities.add({ name : \u0026#39;Citizens Bank Park\u0026#39;, position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534), point : { pixelSize : 5, color : Cesium.Color.RED, outlineColor : Cesium.Color.WHITE, outlineWidth : 2 }, label : { text : \u0026#39;Citizens Bank Park\u0026#39;, font : \u0026#39;14pt monospace\u0026#39;, style: Cesium.LabelStyle.FILL_AND_OUTLINE, outlineWidth : 2, verticalOrigin : Cesium.VerticalOrigin.BOTTOM, pixelOffset : new Cesium.Cartesian2(0, -9) } }); viewer.zoomTo(viewer.entities); By default, labels are horizontally and vertically centered. Since the label and point share the same position, they overlap on screen. To avoid this, specify the label origin as VerticalOrigin.BOTTOM and set the pixel offset to (0, -9). Replace the point with a billboard, which is a marker that always faces the user.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var citizensBankPark = viewer.entities.add({ position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534), billboard : { image : \u0026#39;//cesiumjs.org/tutorials/Visualizing-Spatial-Data/images/Philadelphia_Phillies.png\u0026#39;, width : 64, height : 64 }, label : { text : \u0026#39;Citizens Bank Park\u0026#39;, font : \u0026#39;14pt monospace\u0026#39;, style: Cesium.LabelStyle.FILL_AND_OUTLINE, outlineWidth : 2, verticalOrigin : Cesium.VerticalOrigin.TOP, pixelOffset : new Cesium.Cartesian2(0, 32) } }); For more customization options, see the Sandcastle Labels and Billboards examples.\n3D Models CesiumJS supports creating 3D models via glTF (runtime asset format). You can find example models in the 3D models Sandcastle.\nSet a position and URI to a glTF model to create a model entity.\n1 2 3 4 5 6 7 8 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var entity = viewer.entities.add({ position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706), model : { uri : \u0026#39;../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb\u0026#39; } }); viewer.trackedEntity = entity; By default, the model is upright and faces east. Control the model\u0026rsquo;s orientation by specifying a Quaternion for the Entity.orientation property. This controls the model\u0026rsquo;s heading, pitch, and roll.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706); var heading = Cesium.Math.toRadians(45.0); var pitch = Cesium.Math.toRadians(15.0); var roll = Cesium.Math.toRadians(0.0); var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(heading, pitch, roll)); var entity = viewer.entities.add({ position : position, orientation : orientation, model : { uri : \u0026#39;../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb\u0026#39; } }); viewer.trackedEntity = entity; For more advanced model features, see the 3D Models tutorial. If you create your own models, be sure to check our post on glTF Tips for Artists.\nThe Property System All values we define for entities are stored as property objects. For example, see the value of Wyoming\u0026rsquo;s outline:\n1 console.log(typeof wyoming.polygon.outline); outline is an instance of ConstantProperty. This tutorial uses a shorthand called implicit property conversion, which automatically takes raw values and creates the corresponding Property under the hood. Without this shorthand, we would have to write a longer version of the initial example:\n1 2 3 4 5 6 7 8 9 10 var wyoming = new Cesium.Entity(); wyoming.name = \u0026#39;Wyoming\u0026#39;; var polygon = new Cesium.PolygonGraphics(); polygon.material = new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.5)); polygon.outline = new Cesium.ConstantProperty(true); polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.BLACK); wyoming.polygon = polygon; viewer.entities.add(wyoming); Properties are used because the Entity API can represent not only constant values but also values that change over time. See the Callback Property and Interpolation Sandcastle examples for some time-dynamic properties.\nResources For examples on how to style and create entities using GeoJSON and CZML, see the Cesium Workshop Tutorial.\nCesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2019-05-22T02:15:02Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-4-spatial-data-visualization-part-2/","title":"[CesiumJS] Cesium Intermediate Tutorial 4 - Spatial Data Visualization (Part 2)"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\nCamera The Camera in CesiumJS controls the view of the scene. There are many ways to manipulate the Camera, such as rotate, zoom, pan, and flyTo. CesiumJS has mouse and touch events for handling Camera interactions, as well as an API for programmatically manipulating the camera. Learn how to use the Camera API and customize Camera controls.\nDefault Camera Behavior Open the Hello World example in Sandcastle to experience the default camera controls. The default operations are as follows:\nEnglish Version Mouse Action 3D 2D Columbus View Left click + drag Rotate around the globe Translate over the map Translate over the map Right click + drag Zoom in and out Zoom in and out Zoom in and out Middle wheel scrolling Zoom in and out Zoom in and out Zoom in and out Middle click + drag Tilt the globe No action Tilt the map Chinese Version Mouse Action 3D 2D Columbus View Left click + drag Rotate globe Pan map Pan map Right click + drag Zoom Zoom Zoom Middle wheel Zoom Zoom Zoom Middle click + drag Tilt globe No action Tilt globe Use the setView function to set the Camera\u0026rsquo;s position and orientation. The destination can be a Cartesian3 or Rectangle, and the orientation can be heading/pitch/roll or direction/up. Heading, pitch, and roll are defined in radians. Heading is the rotation from local north with positive angles increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch is above the plane. Negative pitch is below the plane. Roll is the first rotation applied around the local east axis.\n1 2 3 4 5 6 7 8 camera.setView({ destination: new Cesium.Cartesian3(x, y, z), orientation: { heading: headingAngle, pitch: pitchAngle, roll: rollAngle } }); 1 2 3 4 5 6 7 8 viewer.camera.setView({ destination: Cesium.Rectangle.fromDegrees(west, south, east, north), orientation: { heading: headingAngle, pitch: pitchAngle, roll: rollAngle } }); All of the above parameters are optional. If not specified, parameter values will default to the current Camera position and orientation.\nCustom Camera Mouse or Keyboard Events Create our own event handlers to control Camera orientation based on mouse direction, and keyboard keys to move the Camera forward, left, right, up, and down. Start by disabling the default event handlers. Add the following code after (`javascript var viewe=\u0026hellip;`):\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 var scene = viewer.scene; var canvas = viewer.canvas; canvas.setAttribute(\u0026#39;tabindex\u0026#39;, \u0026#39;0\u0026#39;); // needed to put focus on the canvas canvas.onclick = function() { canvas.focus(); }; var ellipsoid = viewer.scene.globe.ellipsoid; // disable the default event handlers scene.screenSpaceCameraController.enableRotate = false; scene.screenSpaceCameraController.enableTranslate = false; scene.screenSpaceCameraController.enableZoom = false; scene.screenSpaceCameraController.enableTilt = false; scene.screenSpaceCameraController.enableLook = false; Create variables to record the current mouse position, then flag and track Camera movement:\n1 2 3 4 5 6 7 8 9 10 11 var startMousePosition; var mousePosition; var flags = { looking: false, moveForward: false, moveBackward: false, moveUp: false, moveDown: false, moveLeft: false, moveRight: false }; Add an event handler to set the flag and record the current mouse position when the left mouse button is clicked:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 var handler = new Cesium.ScreenSpaceEventHandler(canvas); handler.setInputAction(function(movement) { flags.looking = true; mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position); }, Cesium.ScreenSpaceEventType.LEFT_DOWN); handler.setInputAction(function(movement) { mousePosition = movement.endPosition; }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function(position) { flags.looking = false; }, Cesium.ScreenSpaceEventType.LEFT_UP); Create keyboard event handlers to toggle Camera movement flags. We set flags for the following keys and behaviors:\nw Camera moves forward. s Camera moves backward. a Camera moves left. d Camera moves right. q Camera moves up. e Camera moves down. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 function getFlagForKeyCode(keyCode) { switch (keyCode) { case \u0026#39;W\u0026#39;.charCodeAt(0): return \u0026#39;moveForward\u0026#39;; case \u0026#39;S\u0026#39;.charCodeAt(0): return \u0026#39;moveBackward\u0026#39;; case \u0026#39;Q\u0026#39;.charCodeAt(0): return \u0026#39;moveUp\u0026#39;; case \u0026#39;E\u0026#39;.charCodeAt(0): return \u0026#39;moveDown\u0026#39;; case \u0026#39;D\u0026#39;.charCodeAt(0): return \u0026#39;moveRight\u0026#39;; case \u0026#39;A\u0026#39;.charCodeAt(0): return \u0026#39;moveLeft\u0026#39;; default: return undefined; } } document.addEventListener(\u0026#39;keydown\u0026#39;, function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== \u0026#39;undefined\u0026#39;) { flags[flagName] = true; } }, false); document.addEventListener(\u0026#39;keyup\u0026#39;, function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== \u0026#39;undefined\u0026#39;) { flags[flagName] = false; } }, false); Now when a flag indicates an event has occurred (is true), we update the camera. We add an onTick listener to the clock:\n1 2 3 viewer.clock.onTick.addEventListener(function(clock) { var camera = viewer.camera; }); Next, we make the Camera point in the direction the mouse is pointing. Add the following code to the event listener function after the variable declaration:\n1 2 3 4 5 6 7 8 9 10 11 12 if (flags.looking) { var width = canvas.clientWidth; var height = canvas.clientHeight; // Coordinate (0.0, 0.0) will be where the mouse was clicked. var x = (mousePosition.x - startMousePosition.x) / width; var y = -(mousePosition.y - startMousePosition.y) / height; var lookFactor = 0.05; camera.lookRight(x * lookFactor); camera.lookUp(y * lookFactor); } lookRight and lookUp only require an angle parameter representing the rotation angle. We convert the mouse coordinates to the range (-1.0, 1.0), with coordinate (0.0, 0.0) at the center of the canvas. The distance of the mouse from the center determines the rotation speed. Positions closer to the center move the Camera slower, while positions farther from the center move the Camera faster.\nFinally, add code to move the Camera position. Then add the following code to the event handler function:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // Change movement speed based on the distance of the camera to the surface of the ellipsoid. var cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height; var moveRate = cameraHeight / 100.0; if (flags.moveForward) { camera.moveForward(moveRate); } if (flags.moveBackward) { camera.moveBackward(moveRate); } if (flags.moveUp) { camera.moveUp(moveRate); } if (flags.moveDown) { camera.moveDown(moveRate); } if (flags.moveLeft) { camera.moveLeft(moveRate); } if (flags.moveRight) { camera.moveRight(moveRate); } The moveForward, moveBackward, moveUp, moveDown, moveLeft, and moveRight methods only require a distance parameter (in meters) for moving the Camera. When each key is pressed, the Camera moves a fixed distance along the ellipsoid surface. The closer the Camera is to the ground, the slower it moves.\nComplete code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var scene = viewer.scene; var canvas = viewer.canvas; canvas.setAttribute(\u0026#39;tabindex\u0026#39;, \u0026#39;0\u0026#39;); // needed to put focus on the canvas canvas.onclick = function() { canvas.focus(); }; var ellipsoid = viewer.scene.globe.ellipsoid; // disable the default event handlers scene.screenSpaceCameraController.enableRotate = false; scene.screenSpaceCameraController.enableTranslate = false; scene.screenSpaceCameraController.enableZoom = false; scene.screenSpaceCameraController.enableTilt = false; scene.screenSpaceCameraController.enableLook = false; var startMousePosition; var mousePosition; var flags = { looking : false, moveForward : false, moveBackward : false, moveUp : false, moveDown : false, moveLeft : false, moveRight : false }; var handler = new Cesium.ScreenSpaceEventHandler(canvas); handler.setInputAction(function(movement) { flags.looking = true; mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position); }, Cesium.ScreenSpaceEventType.LEFT_DOWN); handler.setInputAction(function(movement) { mousePosition = movement.endPosition; }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function(position) { flags.looking = false; }, Cesium.ScreenSpaceEventType.LEFT_UP); function getFlagForKeyCode(keyCode) { switch (keyCode) { case \u0026#39;W\u0026#39;.charCodeAt(0): return \u0026#39;moveForward\u0026#39;; case \u0026#39;S\u0026#39;.charCodeAt(0): return \u0026#39;moveBackward\u0026#39;; case \u0026#39;Q\u0026#39;.charCodeAt(0): return \u0026#39;moveUp\u0026#39;; case \u0026#39;E\u0026#39;.charCodeAt(0): return \u0026#39;moveDown\u0026#39;; case \u0026#39;D\u0026#39;.charCodeAt(0): return \u0026#39;moveRight\u0026#39;; case \u0026#39;A\u0026#39;.charCodeAt(0): return \u0026#39;moveLeft\u0026#39;; default: return undefined; } } document.addEventListener(\u0026#39;keydown\u0026#39;, function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== \u0026#39;undefined\u0026#39;) { flags[flagName] = true; } }, false); document.addEventListener(\u0026#39;keyup\u0026#39;, function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== \u0026#39;undefined\u0026#39;) { flags[flagName] = false; } }, false); viewer.clock.onTick.addEventListener(function(clock) { var camera = viewer.camera; if (flags.looking) { var width = canvas.clientWidth; var height = canvas.clientHeight; // Coordinate (0.0, 0.0) will be where the mouse was clicked. var x = (mousePosition.x - startMousePosition.x) / width; var y = -(mousePosition.y - startMousePosition.y) / height; var lookFactor = 0.05; camera.lookRight(x * lookFactor); camera.lookUp(y * lookFactor); } // Change movement speed based on the distance of the camera to the surface of the ellipsoid. var cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height; var moveRate = cameraHeight / 100.0; if (flags.moveForward) { camera.moveForward(moveRate); } if (flags.moveBackward) { camera.moveBackward(moveRate); } if (flags.moveUp) { camera.moveUp(moveRate); } if (flags.moveDown) { camera.moveDown(moveRate); } if (flags.moveLeft) { camera.moveLeft(moveRate); } if (flags.moveRight) { camera.moveRight(moveRate); } }); Full code available here)\nCamera Camera represents the state of the Camera\u0026rsquo;s current position, orientation, reference frame, and view frustum. The Camera vectors above are orthogonal in each frame. The *move*_ and _zoom** functions translate the Camera\u0026rsquo;s position along its direction or a specified direction vector. The direction remains fixed.\nThe *look*_ and _twist** functions rotate the Camera\u0026rsquo;s direction, such as up or right vectors. The position remains fixed.\nThe *rotate** functions rotate the position and direction based on a given vector.\nFunctions set the Camera position and orientation given an extent or position and target. For example:\n1 2 3 4 5 6 var west = Cesium.Math.toRadians(-77.0); var south = Cesium.Math.toRadians(38.0); var east = Cesium.Math.toRadians(-72.0); var north = Cesium.Math.toRadians(42.0); var extent = new Cesium.Extent(west, south, east, north); camera.viewExtent(extent, Cesium.Ellipsoid.WGS84); Create a ray variable by picking the Camera\u0026rsquo;s position through a pixel. This method can be used for picking, for example:\n1 2 3 // find intersection of the pixel picked and an ellipsoid var ray = camera.getPickRay(mousePosition); var intersection = Cesium.IntersectionTests.rayEllipsoid(ray, Cesium.Ellipsoid.WGS84); Screen space camera controller ScreenSpaceCameraController converts user input (such as mouse and touch) from window coordinates to Camera movement. It contains properties for enabling and disabling different types of input, modifying the amount of inertia, and minimum and maximum zoom distances.\nResources View camera example code in Sandcastle:\nCamera Tutorial Camera API documentation:\nCamera ScreenSpaceCameraController Cesium Chinese Website QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China Fast Access: http://cesium.coinidea.com/\n","date":"2019-05-20T15:43:53Z","permalink":"https://blog.coinidea.com/en/p/cesiumjs-cesium-intermediate-tutorial-3-camera/","title":"[CesiumJS] Cesium Intermediate Tutorial 3 - Camera"},{"content":"vsftpd.conf\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 # Example config file /etc/vsftpd/vsftpd.conf # # The default compiled in settings are fairly paranoid. This sample file # loosens things up a bit, to make the ftp daemon more usable. # Please see vsftpd.conf.5 for all compiled in defaults. # # READ THIS: This example file is NOT an exhaustive list of vsftpd options. # Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd\u0026#39;s # capabilities. # # Allow anonymous FTP? (Beware - allowed by default if you comment this out). anonymous_enable=NO # # Uncomment this to allow local users to log in. # When SELinux is enforcing check for SE bool ftp_home_dir local_enable=YES # # Uncomment this to enable any form of FTP write command. write_enable=YES # # Default umask for local users is 077. You may wish to change this to 022, # if your users expect that (022 is used by most other ftpd\u0026#39;s) local_umask=022 # # Uncomment this to allow the anonymous FTP user to upload files. This only # has an effect if the above global write enable is activated. Also, you will # obviously need to create a directory writable by the FTP user. # When SELinux is enforcing check for SE bool allow_ftpd_anon_write, allow_ftpd_full_access #anon_upload_enable=YES # # Uncomment this if you want the anonymous FTP user to be able to create # new directories. #anon_mkdir_write_enable=YES # # Activate directory messages - messages given to remote users when they # go into a certain directory. dirmessage_enable=YES # # Activate logging of uploads/downloads. xferlog_enable=YES # # Make sure PORT transfer connections originate from port 20 (ftp-data). connect_from_port_20=YES # # If you want, you can arrange for uploaded anonymous files to be owned by # a different user. Note! Using \u0026#34;root\u0026#34; for uploaded files is not # recommended! #chown_uploads=YES #chown_username=whoever # # You may override where the log file goes if you like. The default is shown # below. #xferlog_file=/var/log/xferlog # # If you want, you can have your log file in standard ftpd xferlog format. # Note that the default log file location is /var/log/xferlog in this case. xferlog_std_format=YES # # You may change the default value for timing out an idle session. #idle_session_timeout=600 # # You may change the default value for timing out a data connection. #data_connection_timeout=120 # # It is recommended that you define on your system a unique user which the # ftp server can use as a totally isolated and unprivileged user. #nopriv_user=ftpsecure # # Enable this and the server will recognise asynchronous ABOR requests. Not # recommended for security (the code is non-trivial). Not enabling it, # however, may confuse older FTP clients. #async_abor_enable=YES # # By default the server will pretend to allow ASCII mode but in fact ignore # the request. Turn on the below options to have the server actually do ASCII # mangling on files when in ASCII mode. # Beware that on some FTP servers, ASCII support allows a denial of service # attack (DoS) via the command \u0026#34;SIZE /big/file\u0026#34; in ASCII mode. vsftpd # predicted this attack and has always been safe, reporting the size of the # raw file. # ASCII mangling is a horrible feature of the protocol. #ascii_upload_enable=YES #ascii_download_enable=YES # # You may fully customise the login banner string: ftpd_banner=Welcome to blah FTP service. # # You may specify a file of disallowed anonymous e-mail addresses. Apparently # useful for combatting certain DoS attacks. #deny_email_enable=YES # (default follows) #banned_email_file=/etc/vsftpd/banned_emails # # You may specify an explicit list of local users to chroot() to their home # directory. If chroot_local_user is YES, then this list becomes a list of # users to NOT chroot(). # (Warning! chroot\u0026#39;ing can be very dangerous. If using chroot, make sure that # the user does not have write access to the top level directory within the # chroot) chroot_local_user=YES chroot_list_enable=NO # (default follows) chroot_list_file=/etc/vsftpd/chroot_list # # You may activate the \u0026#34;-R\u0026#34; option to the builtin ls. This is disabled by # default to avoid remote users being able to cause excessive I/O on large # sites. However, some broken FTP clients such as \u0026#34;ncftp\u0026#34; and \u0026#34;mirror\u0026#34; assume # the presence of the \u0026#34;-R\u0026#34; option, so there is a strong case for enabling it. #ls_recurse_enable=YES # # When \u0026#34;listen\u0026#34; directive is enabled, vsftpd runs in standalone mode and # listens on IPv4 sockets. This directive cannot be used in conjunction # with the listen_ipv6 directive. listen=YES # # This directive enables listening on IPv6 sockets. By default, listening # on the IPv6 \u0026#34;any\u0026#34; address (::) will accept connections from both IPv6 # and IPv4 clients. It is not necessary to listen on *both* IPv4 and IPv6 # sockets. If you want that (perhaps because you want to listen on specific # addresses) then you must run two copies of vsftpd with two configuration # files. # Make sure, that one of the listen options is commented !! listen_ipv6=NO pam_service_name=vsftpd userlist_enable=YES tcp_wrappers=YES local_root=/ftp anon_root=/ftp use_localtime=YES user_config_dir=/etc/vsftpd/userconfig pasv_enable=yes pasv_min_port=41000 pasv_max_port=42000 allow_writeable_chroot=YES listen_port=21 xferlog_file=/var/log/vsftpd.log pasv_address=your_ip pasv_addr_resolve=yes pasv_promiscuous=YES user_list\n1 # Comment out everything in this file chroot_list\n1 2 ftpuser ftpsubuser /etc/vsftpd/userconfig/ftpsubuser\n1 local_root=/ftp/ftpsubuser/ Commands to execute:\n1 2 3 4 5 sudo useradd ftpuser -d /ftp -s /sbin/nologin -m passwd ftpuser sudo useradd ftpsubuser -d /ftp/ftpsubuser -s /sbin/nologin -m passwd ftpsubuser ","date":"2019-04-10T02:56:05Z","permalink":"https://blog.coinidea.com/en/p/vsftpd-vsftpd-passive-mode-configuration/","title":"[vsftpd] vsftpd Passive Mode Configuration"},{"content":"A recent project involved MongoDB clusters, Spark clusters, Hadoop clusters, Python 2.7, Python 3.5, various recommendation algorithms, Java Resin environment, LNMP environment, vsftpd, and more. Because it needed to be deployed across intranet, testing, and production environments, each deployment was painful. This is where Docker\u0026rsquo;s benefits really shone \u0026ndash; packing Python environments, LNMP environments, vsftpd, and everything else into Docker containers was extremely satisfying. After 2 months of deployment and integration testing, I compiled some practical Docker commands. System environment: CentOS 7\nDownload, install Docker, and start the service\nhttps://download.docker.com/linux/centos/7/x86_64/stable/Packages/\nDownload docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm\n1 2 yum install docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm service docker start Common Docker commands\nFix error: WARNING: IPv4 forwarding is disabled. Networking will not work.\nStep 1: On the host machine, run echo \u0026quot;net.ipv4.ip_forward=1\u0026quot; \u0026gt;\u0026gt;/usr/lib/sysctl.d/00-system.conf\nStep 2: Restart network and Docker services\n1 [root@localhost /]# systemctl restart network \u0026amp;\u0026amp; systemctl restart docker Failed to get D-Bus connection: Operation not permitted\n1 docker run -d --name centos7 --privileged=true --net=host -v /home/code:/home/code centos:mysql_python3_jdk1.8 /usr/sbin/init Run a Docker container for a long time with host path mounting\n1 docker run -dit -v /home/code:/home/code python35:latest /bin/bash Enter a running Docker container\n1 docker exec -it container_id /bin/bash Start a container image\n1 docker run -it python35:latest /bin/bash Docker export:\n1 docker export -o /home/python35.tar container_id docker save *.tar\nDocker import:\n1 docker import /home/python35.tar docker load \u0026lt; *.tar\nDocker tagging\n1 docker tag image_id REPOSITORY:TAG Docker specify host network\n1 docker run -dit --net=host python35:latest /bin/bash Docker sync container and host time\n1 docker run -dit -v /etc/localtime:/etc/localtime python35:latest /bin/bash Install JDK 1.8\n1 yum install java-1.8.0-openjdk* -y Install MySQL 5.6\n1 2 3 4 5 6 7 8 rpm -Uvh http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm yum -y install mysql-community-server systemctl enable mysqld systemctl start mysqld Initialize: mysql_secure_installation GRANT ALL PRIVILEGES ON *.* TO \u0026#39;root\u0026#39;@\u0026#39;%\u0026#39; IDENTIFIED BY \u0026#39;remote_login_password\u0026#39; WITH GRANT OPTION; FLUSH PRIVILEGES; Python 3 encoding\n1 echo \u0026#39;export LANG=zh_CN.UTF-8\u0026#39; \u0026gt;\u0026gt; ~/.bashrc ","date":"2019-04-10T02:45:13Z","permalink":"https://blog.coinidea.com/en/p/dockerdocker-common-commands-cheat-sheet/","title":"[Docker]Docker Common Commands Cheat Sheet"},{"content":"Previously, I had a service using Nginx as a reverse proxy. Due to the high volume of traffic, I wanted to do some simple access statistics at the Nginx layer. I found that Nginx\u0026rsquo;s default access_log writes everything to a single file, which is very inconvenient. After some research, many people suggested using shell scripts to solve this problem. Finally, I found a better solution \u0026ndash; Nginx supports the following configuration:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 server { listen 8082; server_name your ip; if ($time_iso8601 ~ \u0026#34;^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})\u0026#34;){ set $year \\$1; set $month \\$2; set $day \\$3; set $hour \\$4; set $minutes \\$5; set $seconds \\$6; } access_log logs/8082_$year-$month-$day.log; error_log logs/8082.error; # Forward all requests location / { proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://localhost:8082; } } ","date":"2019-04-10T02:30:15Z","permalink":"https://blog.coinidea.com/en/p/lnmp-nginx-access_log-daily-rotation/","title":"[LNMP] Nginx access_log Daily Rotation"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\nThe National Geographic Information Public Service Platform \u0026ldquo;Tianditu\u0026rdquo; 2018 edition has upgraded the Tianditu application development process. The Tianditu API and service interfaces have been fully upgraded to the tianditu.gov.cn government domain, supporting HTTP/HTTPS protocols. The original service domain tianditu.com will continue to be retained.\nTo ensure the stability and reliability of Tianditu\u0026rsquo;s geographic information public services and to better support developers with geographic information application development, starting immediately, all Tianditu API and service interface calls require a development license (Key). You can register and apply for free at the Tianditu API website console. Please make adjustments as soon as possible. Tianditu will stop supporting API and service calls without a development license (Key) on January 1, 2019. Before that date, unauthorized APIs and services will continue to work normally.\nPlease register appropriately as an individual or organization user. Enterprise and institutional users with higher service call volume requirements should register as organizational users and become certified enterprise developers. Original link:\nhttp://lbs.tianditu.gov.cn/authorization/authorization.html\nCesium Chinese Community QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\n","date":"2019-01-17T02:54:47Z","permalink":"https://blog.coinidea.com/en/p/cesiumjstianditu-application-development-license-application-guide-update-your-tianditu-data-interface-asap/","title":"[CesiumJS]Tianditu Application Development License Application Guide - Update Your Tianditu Data Interface ASAP"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\nCesium supports rendering and adding high-resolution imagery (map) layers from several standard services. Layers can be ordered and blended together. The brightness, contrast, gamma, hue, and saturation of each layer can be dynamically changed. This tutorial introduces the concept of imagery layers and the related Cesium APIs.\nQuick Start Let\u0026rsquo;s skip the details for now and write some code to add imagery layers. Open the Hello World example in Sandcastle. This example creates a Viewer widget, which renders Bing Maps by default. We can specify a different base layer by providing additional parameters to the Viewer constructor. Let\u0026rsquo;s use a layer from Esri ArcGIS MapServer:\n1 2 3 4 5 6 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;, { imageryProvider : new Cesium.ArcGisMapServerImageryProvider({ url : \u0026#39;//services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer\u0026#39; }), baseLayerPicker : false }); After modifying the example, press F8 to run:\nWe can scroll the mouse wheel to zoom in and out to see the actual imagery streaming in action.\nNext, add another layer: NASA Black Marble imagery based on Tile Map Service (TMS):\n1 2 3 4 5 6 var layers = viewer.scene.imageryLayers; var blackMarble = layers.addImageryProvider(new Cesium.createTileMapServiceImageryProvider({ url : \u0026#39;//cesiumjs.org/tilesets/imagery/blackmarble\u0026#39;, maximumLevel : 8, credit : \u0026#39;Black Marble imagery courtesy NASA Earth Observatory\u0026#39; })); Because the Black Marble layer was added last and covers the entire globe, it covers the Esri layer. We could move the Black Marble layer to the bottom with layers.lower(blackMarble);, but to better understand the relationship between these two layers, let\u0026rsquo;s blend it with the Esri layer:\n1 blackMarble.alpha = 0.5; // 0.0 is transparent. 1.0 is opaque. Next, increase the brightness of the lights:\n1 blackMarble.brightness = 2.0; // \u0026gt; 1.0 increases brightness. \u0026lt; 1.0 decreases. Finally, add a single image as a third layer for a specific extent:\n1 2 3 4 layers.addImageryProvider(new Cesium.SingleTileImageryProvider({ url : \u0026#39;../images/Cesium_Logo_overlay.png\u0026#39;, rectangle : Cesium.Rectangle.fromDegrees(-75.0, 28.0, -67.0, 29.75) })); Complete code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;, { imageryProvider : new Cesium.ArcGisMapServerImageryProvider({ url : \u0026#39;//services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer\u0026#39; }), baseLayerPicker : false }); var layers = viewer.scene.imageryLayers; var blackMarble = layers.addImageryProvider(new Cesium.createTileMapServiceImageryProvider({ url : \u0026#39;//cesiumjs.org/tilesets/imagery/blackmarble\u0026#39;, maximumLevel : 8, credit : \u0026#39;Black Marble imagery courtesy NASA Earth Observatory\u0026#39; })); blackMarble.alpha = 0.5; // 0.0 is transparent. 1.0 is opaque. blackMarble.brightness = 2.0; // \u0026gt; 1.0 increases brightness. \u0026lt; 1.0 decreases. layers.addImageryProvider(new Cesium.SingleTileImageryProvider({ url : \u0026#39;../images/Cesium_Logo_overlay.png\u0026#39;, rectangle : Cesium.Rectangle.fromDegrees(-75.0, 28.0, -67.0, 29.75) })); View the complete example in Sandcastle.\nExisting Imagery Layers The ion Assets tab in Sandcastle contains imagery layer applications hosted by Cesium ion, which can be used in Cesium applications by adding just a few lines of code.\nImageryProvider High-resolution imagery like the first two layers used above is too large to fit in memory or even on a single disk, so the imagery is divided into smaller images called tiles that can be streamed to the client based on the view. Cesium supports requesting tiles using ImageryProvider with several standards. Most ImageryProviders use REST interfaces over HTTP to request tiles. ImageryProviders differ based on the format and organization of the requests. Cesium includes the following built-in ImageryProviders:\nWeb Map Service (WMS) - An OGC standard for requesting map tiles from distributed geospatial databases. In Cesium, see WebMapServiceImageryProvider. Tile Map Service (TMS) - A REST interface for accessing tiles. Tiles can be generated using MapTiler or GDAL2Tiles. See TileMapServiceImageryProvider. OpenGIS Web Map Tile Service (WMTS) - An OGC standard for serving pre-rendered georeferenced tiles over the internet. In Cesium, see WebMapTileServiceImageryProvider. OpenStreetMap - Access OpenStreetMap tiles or any Slippy map tiles. There are several ways to host these tiles. In Cesium, see createOpenStreetMapImageryProvider. Bing Maps - Use the Bing Maps REST Services to access tiles. Create Bing Maps keys at https://www.bingmapsportal.com/. In Cesium, see BingMapsImageryProvider. Esri ArcGIS MapServer - Use the ArcGIS Server REST API to access tiles on an ArcGIS MapServer. In Cesium, see ArcGisMapServerImageryProvider. Google Earth Enterprise - Provides access to imagery stored in Google Earth Enterprise servers. In Cesium, see GoogleEarthImageryProvider. Mapbox - Use the Mapbox API to access tiles. Create an account and provide an access token. In Cesium, see MapboxImageryProvider. Standard image files - Create imagery layers from images. In Cesium, see SingleTileImageryProvider. Custom tiling schemes - Using UrlTemplateImageryProvider, we can connect to a wide variety of imagery sources by using URL templates. For example, a TMS URL template is //cesiumjs.org/tilesets/imagery/naturalearthii/{z}/{x}/{reverseY}.jpg. Tile coordinates - Shows how the globe is divided into tiles in a particular tiling scheme by drawing a border around each tile and labeling it with its level, X, and Y coordinates. We can access other imagery services by implementing the ImageryProvider interface. If you do so and think it\u0026rsquo;s generally useful, please contribute it to Cesium for everyone\u0026rsquo;s benefit.\nSee the reference documentation to learn how to construct a specific imagery provider. Let\u0026rsquo;s look at SingleTileImageryProvider since many imagery providers share its constructor properties:\nurl - The URL of the image. Like many imagery providers, this is the only required property. In other imagery providers, this URL points to the server or the root URL of the service. extent - Optional. The longitude/latitude rectangle that the image should cover. By default, it covers the entire globe. credit - Optional. A string credit for the data source, displayed on the canvas. Some imagery providers, such as BingMapsImageryProvider and ArcGIS Server REST API, can retrieve credits or logos directly from their services. proxy - Optional. A proxy for requesting the service, which can enable cross-origin resource sharing. Cross-Origin Resource Sharing For security reasons, today\u0026rsquo;s web browsers work hard to prevent JavaScript code from reading image pixels from different sites. In particular, if a WebGL application like Cesium accesses images from a different hostname or port and the server doesn\u0026rsquo;t explicitly allow the images to be used this way, using those images as textures is prohibited. The server indicates that images don\u0026rsquo;t contain confidential information and that it\u0026rsquo;s safe for other sites to read their pixels by including Cross-Origin Resource Sharing (CORS) headers in the HTTP response.\nUnfortunately, not all imagery services support CORS. For those that don\u0026rsquo;t, a proxy server with the same origin as the website hosting Cesium must be used. When using such a proxy, for the web browser and Cesium client, the tiles appear as though they come from the same origin as the Cesium-based website. To use a proxy with an imagery provider, use the proxy property when constructing the imagery provider. Cesium includes a simple proxy written in Node.js for development purposes.\n1 2 3 4 layers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({ url : \u0026#39;//server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer\u0026#39;, proxy : new Cesium.DefaultProxy(\u0026#39;/proxy/\u0026#39;) })); If you\u0026rsquo;re hosting public imagery, we encourage enabling CORS as described in this article rather than using a proxy.\nImageryProvider vs. Layers So far, we haven\u0026rsquo;t explicitly distinguished between ImageryProvider and layers. An ImageryProvider requests imagery using a specific service, while a layer represents the displayed imagery from an ImageryProvider. The code:\n1 var layer = layers.addImageryProvider(imageryProvider); is shorthand for:\n1 2 var layer = new ImageryLayer(imageryProvider); layers.add(layer); We typically construct an imagery provider only to create a layer, then we use its properties such as show, alpha, brightness, and contrast. See ImageryLayer. Decoupling imagery providers from layers makes it easy to add new imagery providers.\nLike the layers variable in the examples above, the layer collection determines the drawing order of layers. Layers are drawn from bottom to top in the order they were added. The layer collection is operated on using functions such as add, remove, and get, like any other collection in Cesium. Additionally, layers can be reordered using raise, raiseToTop, lower, and lowerToBottom. See ImageryLayerCollection.\nResources Imagery layers examples from Sandcastle:\nImagery Layers - Code samples from this tutorial Imagery Layers Manipulation - Layers from multiple data sources with independent transparency adjustment Imagery Adjustment - Adjust layer brightness, contrast, gamma, hue, and saturation Additional reference documentation:\nAll imagery providers ImageryLayer ImageryLayerCollection Cesium Chinese Community QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\n","date":"2018-12-23T12:19:39Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-intermediate-tutorial-2-imagery-layers/","title":"[CesiumJS]Cesium Intermediate Tutorial 2 - Imagery Layers"},{"content":"Problem Description Recently, my server ran into an issue where it would frequently kill my Tomcat process when memory ran low. Since the overall traffic isn\u0026rsquo;t very high, LNMP and Tomcat are currently running on the same machine, but this caused Tomcat-related Java applications to become unavailable.\n1 free -m Checking the memory usage, I found the operating system had only about 60MB of memory left \u0026ndash; almost completely used up. This situation persisted for about a month, and it was a constant source of frustration. I considered adding more memory but thought it was too expensive. When resources are insufficient, there are generally two approaches: the first is to add resources, and the second is to optimize existing resources. For someone on a budget like me, the second approach is usually my first choice.\nInitially, I thought Tomcat itself or some other process was consuming too much memory. After running:\n1 top I found that php-fpm processes were often the ones consuming the most memory.\nTo view the top 40 memory-consuming processes:\n1 ps auxw | head -1; ps auxw | sort -rn -k4 | head -40 I found that php-fpm dominated the top 40 processes, with memory usage ranging from 2% to 7%. The problem was now quite clear \u0026ndash; the culprit was php-fpm.\nSolution You can control the number of php-fpm child processes by configuring the pm.max_children property. First, open the php-fpm configuration file:\n1 vim /etc/php-fpm.d/www.conf pm.max_children defaults to 50. Each process uses 1%-2.5% of memory, which adds up to consuming most of the memory. Try reducing the value \u0026ndash; I set mine to 25 (also referencing other blogs). At the same time, check the following two properties:\npm.max_spare_servers : This value represents the maximum number of idle processes. If idle processes exceed this value, they will be cleaned up. pm.min_spare_servers : The minimum number of idle processes. If idle processes fall below this value, new child processes are created. Neither of these values should exceed the pm.max_children value. Typically, pm.max_spare_servers is set to 60%-80% of the pm.max_children value.\nFinally, restart php-fpm:\n1 service php-fpm restart Check the memory again:\n1 free -m I found there was about 600MB of free memory remaining. Even after starting Tomcat, there was still about 300MB to spare.\nReference: https://www.jb51.net/article/129528.htm\n1 2 Hope this helps! If you need anything else, feel free to let me know. ","date":"2018-12-19T03:01:19Z","permalink":"https://blog.coinidea.com/en/p/lnmpmemory-optimization/","title":"[LNMP]Memory Optimization"},{"content":"Recently, a friend of mine got hit by ransomware. After some research, I found a good website: the No More Ransom Alliance.\nhttps://www.nomoreransom.org/zh/decryption-tools.html\nI\u0026rsquo;ve always believed that technology is neutral. So if you\u0026rsquo;ve been hit by ransomware, you might want to check out the website above \u0026ndash; there might be some solutions available.\n","date":"2018-11-22T07:23:33Z","permalink":"https://blog.coinidea.com/en/p/what-to-do-if-you-get-hit-by-ransomware/","title":"What to Do If You Get Hit by Ransomware"},{"content":"In offline environments (specifically those where you can\u0026rsquo;t use wget or yum), we often need to compile and install Linux-based operating systems ourselves.\nAt that point, version dependencies become a real headache. Of course, we could use Docker to solve this.\nBut if your offline environment also restricts uploads and downloads, and the internal system versions are unpredictable, it becomes an even bigger pain. So I found a great place to download Linux RPM packages:\nhttps://pkgs.org/\nIt solves the problems of operating system compatibility, system version dependencies, and software dependency management.\n","date":"2018-11-22T07:17:03Z","permalink":"https://blog.coinidea.com/en/p/a-great-place-to-download-rpm-packages/","title":"A Great Place to Download RPM Packages"},{"content":"\nIntroduction to Vultr Vultr is a well-known US cloud service provided by Choopa.com. Choopa has been providing global support services for gaming companies, so the company has deployed data centers in 14 countries and regions worldwide, including Tokyo (Japan), Singapore, Los Angeles, Seattle (USA), London (UK), Germany, and more. It offers excellent value for money, with plans starting at just $2.5/month. New users receive $25 upon registration. Click the following link to register \u0026ndash; new users get $25 (you need to pay $10, which means you pay $10 and get $35 in credit): Promotional offer link\nAdvantages of Vultr Numerous data centers: 14 data centers in Japan, the US, Europe, and more. Excellent architecture: All using KVM architecture, SSD solid-state drives, starting from 1000GB/month traffic. Powerful images: Besides common Linux distributions, you can also install custom ISO systems and Windows. Powerful backend: Features including system snapshots, one-click deployment scripts, backups, firewalls, and more. Promotions: Occasional new user registration bonuses, sometimes with rewards up to $100. Flexible billing: Uses hourly billing mode, allowing you to add and remove machines at will. Customer service: Fast response times, usually getting answers within 15 minutes (time zone differences may apply). Pricing and Configuration ","date":"2018-11-15T07:17:56Z","permalink":"https://blog.coinidea.com/en/p/recommending-a-great-overseas-vps-vultr/","title":"Recommending a Great Overseas VPS - Vultr"},{"content":"I\u0026rsquo;ve been writing articles frequently lately and found that Markdown is a very convenient web typesetting standard. For details, see: http://cesiumcn.org/markdown.html | http://cesium.coinidea.com/markdown.html\nCurrently, I\u0026rsquo;ve found that Jianshu and OSChina have excellent Markdown support. However, WordPress doesn\u0026rsquo;t support it, and surprisingly, Zhihu doesn\u0026rsquo;t support it either.\nWordPress Markdown WordPress has plugins that can provide support. Some people online say the WP Editor.MD plugin is excellent, but after using it on my WordPress version, I found it wasn\u0026rsquo;t compatible \u0026ndash; it crashed directly when activated.\nAt that moment, I had a flash of inspiration and went directly to the official site https://wordpress.org/plugins/ to look. I found that wp-markdown works quite well.\nAfter activating it, I noticed nothing changed. It turns out you need to configure it. The specific location is: Settings -\u0026gt; Writing.\nZhihu Markdown Zhihu obviously can\u0026rsquo;t install plugins like WordPress. The talented developers online are truly amazing. There\u0026rsquo;s a Chrome plugin called Markdown Here. After installing it, when you right-click in a text input box, a Markdown Here menu appears, which automatically converts rich text content to Markdown formatting \u0026ndash; just copy and paste.\n","date":"2018-11-06T06:29:16Z","permalink":"https://blog.coinidea.com/en/p/markdown-anywhere/","title":"Markdown Anywhere"},{"content":"Cesium Chinese Website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\nThis tutorial will teach readers how to use Cesium\u0026rsquo;s Entity API to draw spatial data such as points, markers, labels, lines, models, shapes, and volumes. No prior knowledge of Cesium is required, but if you have no experience at all, you may want to start with the \u0026ldquo;Getting Started Tutorial\u0026rdquo;.\nWhat is the Entity API? Cesium has a rich API for spatial data, which can be divided into two categories: a low-level API oriented toward graphics developers (commonly called the Primitive API) and a high-level API for data-driven visualization (called the Entity API).\nThe primary goal of the Primitive API is to expose the minimal amount of abstraction needed for the task at hand. It expects us to think like graphics programmers and use graphics terminology. Its structure is designed to provide the most performant and flexible implementation for a given type of visualization, rather than API consistency. Loading a model is different from creating a billboard, and both are completely different from creating a polygon. Each type of visualization has its own unique characteristics. Furthermore, they each have different performance characteristics and require following different best practices. While it is powerful and flexible, most applications provide higher-level service interfaces than the Primitive API\u0026rsquo;s level of abstraction.\nThe purpose of the Entity API is to expose a set of consistently designed high-level objects that aggregate related visualization and information into a unified data structure we call an Entity. It lets us focus on presenting our data rather than worrying about the underlying mechanisms of visualization. It also provides constructs that make it easy to build complex, time-dynamic visualizations that naturally fit with static data. While the Entity API actually uses the Primitive API behind the scenes, this is an implementation detail we (almost) never need to concern ourselves with. By applying various heuristics to the data we provide, the Entity API is able to deliver flexible, high-performance visualization while exposing a consistent, easy-to-learn, and easy-to-use interface.\nOur First Entity One of the basic ways to learn the Entity API is by looking at some code. To keep things simple, we\u0026rsquo;ll build on CesiumSandcastle\u0026rsquo;s Hello World example. If you\u0026rsquo;re developing Cesium locally, feel free to use your own application.\nSuppose we want to add a polygon of the US state Wyoming from a list of longitudes and latitudes. (Wyoming was chosen because it\u0026rsquo;s a simple polygon.) We can copy and paste the following code into Sandcastle:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); var wyoming = viewer.entities.add({ name : \u0026#39;Wyoming\u0026#39;, polygon : { hierarchy : Cesium.Cartesian3.fromDegreesArray([ -109.080842,45.002073, -105.91517,45.002073, -104.058488,44.996596, -104.053011,43.002989, -104.053011,41.003906, -105.728954,40.998429, -107.919731,41.003906, -109.04798,40.998429, -111.047063,40.998429, -111.047063,42.000709, -111.047063,44.476286, -111.05254,45.002073]), height : 0, material : Cesium.Color.RED.withAlpha(0.5), outline : true, outlineColor : Cesium.Color.BLACK } }); viewer.zoomTo(wyoming); Click the Run button (or press F8) to see the following image:\nBecause one of our goals is to make Cesium code easy to understand, hopefully this is self-explanatory. We created the Viewer widget, which serves as the foundation for almost all Cesium applications, then added a new Entity via viewer.entities.add. The object we pass to add is just an options parameter providing initial values. The return value is the actual entity instance. Finally, we call viewer.zoomTo to make sure the entity is in view. There are many entity options available, but for now we specify a polygon with a semi-transparent red interior and a black outline. We also give the entity a display name of \u0026ldquo;Wyoming\u0026rdquo;.\nShapes and Volumes With the basic knowledge of creating polygons, and thanks to the homogeneity of the Entity API, we can now create various graphics simply by using the Sandcastle examples as reference. Below is a complete list of supported shapes and volumes. Materials and Outlines Regardless of their geometric definition, all shapes and volumes have a common set of properties that control their appearance. The fill property is a boolean that specifies whether the interior surface is filled, while the outline property controls whether the shape\u0026rsquo;s edges are outlined. When fill is set to true, the material property determines what the fill looks like. In the following example, let\u0026rsquo;s create a semi-transparent blue ellipse. By default, fill is true and outline is false, so we only need to specify the material.\n1 2 3 4 5 6 7 8 9 10 11 var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0), ellipse : { semiMinorAxis : 250000.0, semiMajorAxis : 400000.0, material : Cesium.Color.BLUE.withAlpha(0.5) } }); viewer.zoomTo(viewer.entities); var ellipse = entity.ellipse; // For upcoming examples Image We can also specify the material as an image URL:\n1 ellipse.material = \u0026#39;//cesiumjs.org/tutorials/images/cats.jpg\u0026#39;; In both cases above, a ColorMaterialProperty or ImageMaterialProperty is automatically created for us during assignment. For more complex materials, we need to create a material property instance ourselves. Currently, entity shapes and volumes support color, image, checkerboard, stripe, and grid materials.\nCheckerboard 1 2 3 4 5 ellipse.material = new Cesium.CheckerboardMaterialProperty({ evenColor : Cesium.Color.WHITE, oddColor : Cesium.Color.BLACK, repeat : new Cesium.Cartesian2(4, 4) }); Stripe 1 2 3 4 5 ellipse.material = new Cesium.StripeMaterialProperty({ evenColor : Cesium.Color.WHITE, oddColor : Cesium.Color.BLACK, repeat : 32 }); Grid 1 2 3 4 5 6 ellipse.material = new Cesium.GridMaterialProperty({ color : Cesium.Color.YELLOW, cellAlpha : 0.2, lineCount : new Cesium.Cartesian2(8, 8), lineThickness : new Cesium.Cartesian2(2.0, 2.0) }); Outline Unlike the fill property, outline does not have a corresponding material, but instead relies on two separate properties: outlineColor and outlineWidth. outlineWidth only works on non-Windows systems such as Android, iOS, Linux, and OS X. This is due to limitations in how WebGL is implemented in all three major browser engines on Windows.\n1 2 3 4 ellipse.fill = false; ellipse.outline = true; ellipse.outlineColor = Cesium.Color.YELLOW; ellipse.outlineWidth = 2.0; Polyline Polylines are a special case because they don\u0026rsquo;t have fill or outline properties. Instead, they rely on specialized materials to replace colors. Because of these special materials, polylines with different widths and outline widths will work on all systems.\n1 2 3 4 5 6 7 8 9 10 var entity = viewer.entities.add({ polyline : { positions : Cesium.Cartesian3.fromDegreesArray([-77, 35, -77.1, 35]), width : 5, material : Cesium.Color.RED }}); viewer.zoomTo(viewer.entities); var polyline = entity.polyline // For upcoming examples Polyline Outline 1 2 3 4 5 polyline.material = new Cesium.PolylineOutlineMaterialProperty({ color : Cesium.Color.ORANGE, outlineWidth : 3, outlineColor : Cesium.Color.BLACK }); Polyline Glow 1 2 3 4 polyline.material = new Cesium.PolylineGlowMaterialProperty({ glowPower : 0.2, color : Cesium.Color.BLUE }); Height and Extrusion All shapes that overlay the globe \u0026ndash; currently circles, ellipses, polygons, and rectangles \u0026ndash; can also be placed at an altitude or extruded into a volume. In both cases, the shape or volume still conforms to the curvature of the Earth beneath it.\nFor height, all we need to do is set the height property on the corresponding graphics object, which is the same for all shapes listed above. This might be a good time to mention that Cesium always uses meters, radians, and seconds as units, unless a function explicitly indicates otherwise, such as Cartesian3.fromDegrees. The following line of code elevates the polygon to 250,000 meters above the Earth.\n1 wyoming.polygon.height = 250000; Extruding a shape into a volume is equally easy \u0026ndash; we just need to set the extrudedHeight property. The volume will be generated between height and extrudedHeight. If height is undefined, the volume starts from 0. To create a volume that starts at 200,000 meters and extends to 250,000 meters, we can use the following code. This of course means the volume itself is 50,000 meters tall.\n1 2 wyoming.polygon.height = 200000; wyoming.polygon.extrudedHeight = 250000; Cesium Chinese Community QQ Group: 807482793\nCesium Chinese Website: http://cesiumcn.org/ | China fast access: http://cesium.coinidea.com/\n","date":"2018-11-01T09:09:11Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-intermediate-tutorial-1-spatial-data-visualization-part-1/","title":"[CesiumJS]Cesium Intermediate Tutorial 1 - Spatial Data Visualization (Part 1)"},{"content":"From 2018.06.22 to 2018.10.10, after less than 4 months of operation, the community - Cesium Chinese Website finally exceeded 100 daily unique visitors. Very excited, marking this milestone.\n","date":"2018-10-10T04:48:38Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-chinese-website-daily-uv-exceeds-100/","title":"[CesiumJS]Cesium Chinese Website Daily UV Exceeds 100"},{"content":"The remaining code just adds some additional visualization options. Similar to our previous interactions with HTML elements, we can attach listener functions to toggle shadows and neighborhood polygon visibility.\nLet\u0026rsquo;s start by creating a simple method to toggle the neighborhood polygons. In general, we can hide an entity by setting visibility with Entity.show. However, this only sets visibility for a single entity, and we want to hide or show all neighborhood entities at once.\nWe can achieve this by adding all neighborhood entities to a parent entity, as shown in this example, or simply by using the show property of the EntityCollection. Then we can set visibility for all child entities at once by changing neighborhoods.show.\n1 2 3 4 5 var neighborhoodsElement = document.getElementById(\u0026#39;neighborhoods\u0026#39;); neighborhoodsElement.addEventListener(\u0026#39;change\u0026#39;, function (e) { neighborhoods.show = e.target.checked; }); We can do something similar to toggle shadow visibility:\n1 2 3 4 5 var shadowsElement = document.getElementById(\u0026#39;shadows\u0026#39;); shadowsElement.addEventListener(\u0026#39;change\u0026#39;, function (e) { viewer.shadows = e.target.checked; }); Finally, since 3D Tiles may not load immediately, we can also add a loading indicator that is only removed when the tileset has finished loading (and therefore the promise has resolved).\nCesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/166.html | China fast access: http://cesium.coinidea.com/topic/166.html\n","date":"2018-08-16T07:56:51Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-13-extras/","title":"[CesiumJS]Cesium Getting Started 13 - Extras"},{"content":"To showcase our drone flight, let\u0026rsquo;s experiment with camera modes. We\u0026rsquo;ll keep it simple with two basic camera modes that the user can switch between:\nFree Mode : Default camera controls. Drone Mode : Makes the camera follow the drone through the flight at a fixed distance. Free mode doesn\u0026rsquo;t require any code since it uses the default controls. As for drone follow mode, we can use the camera\u0026rsquo;s built-in entity tracking feature to position the camera and orient it toward the drone with an offset. This keeps the camera at a fixed offset from the specified entity even while it\u0026rsquo;s moving. To track an entity, we simply set viewer.trackedEntity.\nTo switch to free camera mode, we can set viewer.trackedEntity to undefined, then use camera.flyTo() to return to our home view.\nHere are the camera mode functions:\n1 2 3 4 5 6 7 8 9 // Create a follow camera by tracking the drone entity function setViewMode() { if (droneModeElement.checked) { viewer.trackedEntity = drone; } else { viewer.trackedEntity = undefined; viewer.scene.camera.flyTo(homeCameraView); } } To attach this to HTML input, we can attach this function to the change event on the appropriate elements:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var freeModeElement = document.getElementById(\u0026#39;freeMode\u0026#39;); var droneModeElement = document.getElementById(\u0026#39;droneMode\u0026#39;); // Create a follow camera by tracking the drone entity function setViewMode() { if (droneModeElement.checked) { viewer.trackedEntity = drone; } else { viewer.trackedEntity = undefined; viewer.scene.camera.flyTo(homeCameraView); } } freeModeElement.addEventListener(\u0026#39;change\u0026#39;, setCameraMode); droneModeElement.addEventListener(\u0026#39;change\u0026#39;, setCameraMode); Finally, entities are automatically tracked when the user double-clicks on them. If the user starts tracking the drone by clicking, we can add some handling to automatically update the UI:\n1 2 3 4 5 6 viewer.trackedEntityChanged.addEventListener(function() { if (viewer.trackedEntity === drone) { freeModeElement.checked = false; droneModeElement.checked = true; } }); Here are our two camera modes \u0026ndash; we can now freely switch to the drone camera view, which looks like this: Cesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/165.html | China fast access: http://cesium.coinidea.com/topic/165.html\n","date":"2018-08-16T07:55:47Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-12-camera-modes/","title":"[CesiumJS]Cesium Getting Started 12 - Camera Modes"},{"content":"Finally, let\u0026rsquo;s add some mouse interaction. To improve the visibility of our geocache markers, we can change their style to highlight them when the user hovers over a marker.\nTo achieve this, we\u0026rsquo;ll use picking, a Cesium feature that returns data from the 3D scene given a pixel position on the viewer canvas.\nThere are several types of picking:\nScene.pick : Returns an object containing the primitive at the given window position. Scene.drillPick : Returns a list of objects containing all primitives at the given window position. Globe.pick : Returns the intersection point of a given ray with the terrain. Here are some examples of picking operations:\nPicking Demo 3D Tiles Feature Picking Demo Since we want to trigger our highlight effect on hover, we first need to create a mouse action handler. For this, we\u0026rsquo;ll use ScreenSpaceEventHandler, a set of handlers that trigger specified functions on user input actions. ScreenSpaceEventHandler.setInputAction() listens for a user action type ScreenSpaceEventType and runs a specific function, passing the user action as a parameter. Here, we\u0026rsquo;ll pass a function that takes movement as input:\n1 2 var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function(movement) {}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); Next, let\u0026rsquo;s write our highlight function. The handler will pass in mouse movement, from which we can extract a window position to use with pick(). If the pick returns a billboard object, we know we\u0026rsquo;re hovering over a marker. Then, using what we know about Entity styling, we can apply a highlight style.\n1 2 3 4 5 6 7 8 9 10 // If the mouse is over a point of interest, change the entity billboard scale and color handler.setInputAction(function(movement) { var pickedPrimitive = viewer.scene.pick(movement.endPosition); var pickedEntity = (Cesium.defined(pickedPrimitive)) ? pickedPrimitive.id : undefined; // Highlight the currently picked entity if (Cesium.defined(pickedEntity) \u0026amp;\u0026amp; Cesium.defined(pickedEntity.billboard)) { pickedEntity.billboard.scale = 2.0; pickedEntity.billboard.color = Cesium.Color.ORANGERED; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); This successfully triggers the highlight style change on the markers. However, you\u0026rsquo;ll notice that when we move the cursor away, the markers remain highlighted. We can fix this by tracking the last marker and restoring its original style.\nHere is the complete function with marker highlighting and unhighlighting working:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // If the mouse is over a point of interest, change the entity billboard scale and color var previousPickedEntity = undefined; handler.setInputAction(function(movement) { var pickedPrimitive = viewer.scene.pick(movement.endPosition); var pickedEntity = (Cesium.defined(pickedPrimitive)) ? pickedPrimitive.id : undefined; // Unhighlight the previously picked entity if (Cesium.defined(previousPickedEntity)) { previousPickedEntity.billboard.scale = 1.0; previousPickedEntity.billboard.color = Cesium.Color.WHITE; } // Highlight the currently picked entity if (Cesium.defined(pickedEntity) \u0026amp;\u0026amp; Cesium.defined(pickedEntity.billboard)) { pickedEntity.billboard.scale = 2.0; pickedEntity.billboard.color = Cesium.Color.ORANGERED; previousPickedEntity = pickedEntity; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); That\u0026rsquo;s it! We\u0026rsquo;ve now successfully added a mouse movement handler and hover behavior for marker entities. Cesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/164.html | China fast access: http://cesium.coinidea.com/topic/164.html\n","date":"2018-08-16T07:52:08Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-11-interactivity/","title":"[CesiumJS]Cesium Getting Started 11 - Interactivity"},{"content":"Our team sometimes describes Cesium as a 3D game engine for real-world data. However, working with real-world data is much more difficult than working with typical video game assets, because real data can be incredibly high-resolution and requires precise visualization. Fortunately, Cesium has collaborated with the open-source community to develop 3D Tiles, an open specification for streaming massive heterogeneous 3D geospatial datasets.\nUsing streaming technology conceptually similar to Cesium\u0026rsquo;s terrain and imagery, 3D Tiles makes it possible to view enormous models that would otherwise be impossible to interactively view, including building datasets, CAD (or BIM) models, point clouds, and photogrammetry models.\nThe 3D Tiles Inspector is a debugging tool that provides the ability to look under the hood. Here are some demos showcasing different 3D Tiles formats:\nPhotogrammetry Model Building Information Model Point Cloud Model All Formats In our application, we\u0026rsquo;ll use Cesium3DTileset to add realism to our visualization by displaying full 3D models of all buildings in New York! This NYC tileset is hosted on Cesium Ion, and we can add it using IonResource.fromAssetId:\n1 2 // Load the NYC buildings tileset var city = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(3839) })); You may notice that the buildings are not correctly positioned on the ground plane. Fortunately, this is easy to fix. We can adjust the tileset\u0026rsquo;s position by modifying the model matrix (modelMatrix).\nWe can find the current offset of the model modelMatrix from the ground by converting the tileset\u0026rsquo;s bounding sphere to Cartographic, then adding the desired offset and resetting the model matrix.\n1 2 3 4 5 6 7 8 9 10 11 // Adjust the tileset height so its not floating above terrain var heightOffset = -32; city.readyPromise.then(function(tileset) { // Position tileset var boundingSphere = tileset.boundingSphere; var cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center); var surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0); var offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset); var translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3()); tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation); }); Now we have 1.1 million building models streaming in our scene.\n3D Tiles also allows us to adjust our styling using the 3D Tiles styling language. A 3D Tiles style defines expressions for evaluating the color (RGB and transparency) and display of a Cesium3DTileFeature, which is part of the tileset, such as an individual building in the city. Styles are typically based on feature properties stored in the tile\u0026rsquo;s batch table. Feature properties can be height, name, coordinates, construction date, or anything else built into the tileset asset. Styles are defined in JSON, and expressions are written in a small subset of JavaScript designed for styling. Additionally, the styling language provides a set of built-in functions to support common math operations.\nAn example of Cesium3DTileStyle:\n1 2 3 4 var defaultStyle = new Cesium.Cesium3DTileStyle({ color : \u0026#34;color(\u0026#39;white\u0026#39;)\u0026#34;, show : true }); The above code makes our NYC tileset white and always visible. To actually set the tileset\u0026rsquo;s style, we set city.style:\n1 city.style = defaultStyle; We can also define as many styles as we like. For example, making the buildings transparent:\n1 2 3 4 var transparentStyle = new Cesium.Cesium3DTileStyle({ color : \u0026#34;color(\u0026#39;white\u0026#39;, 0.3)\u0026#34;, show : true }); Applying the same style to every feature in our tileset is just scratching the surface. We can also use properties specific to each feature to determine styling. Here\u0026rsquo;s an example of coloring buildings based on their height:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 var heightStyle = new Cesium.Cesium3DTileStyle({ color : { conditions : [ [\u0026#34;${height} \u0026gt;= 300\u0026#34;, \u0026#34;rgba(45, 0, 75, 0.5)\u0026#34;], [\u0026#34;${height} \u0026gt;= 200\u0026#34;, \u0026#34;rgb(102, 71, 151)\u0026#34;], [\u0026#34;${height} \u0026gt;= 100\u0026#34;, \u0026#34;rgb(170, 162, 204)\u0026#34;], [\u0026#34;${height} \u0026gt;= 50\u0026#34;, \u0026#34;rgb(224, 226, 238)\u0026#34;], [\u0026#34;${height} \u0026gt;= 25\u0026#34;, \u0026#34;rgb(252, 230, 200)\u0026#34;], [\u0026#34;${height} \u0026gt;= 10\u0026#34;, \u0026#34;rgb(248, 176, 87)\u0026#34;], [\u0026#34;${height} \u0026gt;= 5\u0026#34;, \u0026#34;rgb(198, 106, 11)\u0026#34;], [\u0026#34;true\u0026#34;, \u0026#34;rgb(127, 59, 8)\u0026#34;] ] } }); To switch between styles, we can add more code to listen to HTML input:\n1 2 3 4 5 6 7 8 9 10 11 12 13 var tileStyle = document.getElementById(\u0026#39;tileStyle\u0026#39;); function set3DTileStyle() { var selectedStyle = tileStyle.options[tileStyle.selectedIndex].value; if (selectedStyle === \u0026#39;none\u0026#39;) { city.style = defaultStyle; } else if (selectedStyle === \u0026#39;height\u0026#39;) { city.style = heightStyle; } else if (selectedStyle === \u0026#39;transparent\u0026#39;) { city.style = transparentStyle; } } tileStyle.addEventListener(\u0026#39;change\u0026#39;, set3DTileStyle); For more examples of 3D Tiles, how to use and adjust styles, check out the 3D Tiles sandcastle demos.\n3D Tiles examples:\nFormats Photogrammetry Model Feature Styling If you have data and need help converting it to 3D Tiles, stay tuned for updates on the Cesium Ion platform! Subscribe for updates here.\nCesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/163.html | China fast access: http://cesium.coinidea.com/topic/163.html\n","date":"2018-08-16T07:49:55Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-10-3d-tiles/","title":"[CesiumJS]Cesium Getting Started 10 - 3D Tiles"},{"content":"Now that we have set up the Viewer configuration, imagery, and terrain for our application, we can add the main focus of our application \u0026ndash; geocache data.\nFor visualization convenience, Cesium supports the popular vector formats GeoJSON and KML, as well as a format our team open-sourced called CZML, which we specifically developed for describing Cesium scenes.\nRegardless of the initial format, all spatial data in Cesium is represented using the Entity API. The Entity API provides an efficient and flexible visualization method for Cesium rendering. A Cesium Entity is a data object that can be paired with styled graphical representations and positioned in space and time. Many simple Entity examples are provided in the test sandbox. To get up to speed on the Entity API, take a break from this application and read the Visualizing Spatial Data tutorial.\nHere are some examples of different entity types:\nPolygon Polyline Billboard Label Once you understand what an Entity looks like, loading datasets with Cesium becomes easy to understand. To read a data file, you need to create a DataSource appropriate for the data format, which will parse the data file hosted at the specified URL and create an EntityCollection containing an Entity for each geospatial object in the dataset. DataSource just defines an interface \u0026ndash; the exact type of data source you need will depend on the data format. For example, KML uses KmlDataSource:\n1 2 3 4 5 6 7 8 var kmlOptions = { camera : viewer.scene.camera, canvas : viewer.scene.canvas, clampToGround : true }; // Load geocache points of interest from a KML file // Data from : http://catalog.opendata.city/dataset/pediacities-nyc-neighborhoods/resource/91778048-3c58-449c-a3f9-365ed203e914 var geocachePromise = Cesium.KmlDataSource.load(\u0026#39;./Source/SampleData/sampleGeocacheLocations.kml\u0026#39;, kmlOptions); The above code reads our sample geocache points from a KML file, calling KmlDataSource.load(options) with some configuration. For a KmlDataSource, the camera and canvas options are required. The clampToGround option enables ground clamping, a popular configuration for making ground geometry entities like polygons and ellipses conform to terrain rather than following the WGS84 ellipsoid surface.\nSince this data is loaded asynchronously, KmlDataSource returns a Promise that will contain all our newly created entities.\nIf you\u0026rsquo;re not familiar with the Promise API for asynchronous functions, \u0026ldquo;asynchronous\u0026rdquo; here basically means you should do what you need with the data in the provided callback function using .then. To actually add this entity collection to the scene, we must wait until the promise is resolved, then add the KmlDataSource to viewer.dataSources:\n1 2 3 4 5 // Add geocache billboard entities to scene and style them geocachePromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); }); By default, these newly created entities have useful features. Clicking will display an Infobox with metadata related to the entity, and double-clicking will zoom to and view the entity. To stop viewing that entity, click the \u0026ldquo;home\u0026rdquo; button, or click the \u0026ldquo;fly out\u0026rdquo; camera icon on the Infobox. Next, we\u0026rsquo;ll add custom styling to improve our application\u0026rsquo;s appearance.\nFor KML and CZML files, declarative styles can be established within the file. However, for this application, let\u0026rsquo;s practice manually styling our entities. To do this, we\u0026rsquo;ll take an approach similar to this styling example, waiting for our data source to load, then iterating through all entities in the data source collection, modifying and adding properties. By default, our geocache point markers are created as Billboards and Labels, so to modify the appearance of these entities, we do this:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // Add geocache billboard entities to scene and style them geocachePromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); // Get the array of entities var geocacheEntities = dataSource.entities.values; for (var i = 0; i \u0026lt; geocacheEntities.length; i++) { var entity = geocacheEntities[i]; if (Cesium.defined(entity.billboard)) { // Entity styling code here } } }); We can improve the appearance of the markers by adjusting their anchor points, removing labels to reduce clutter, and setting a distanceDisplayCondition so that only points within a certain distance from the camera are visible.\n1 2 3 4 5 6 7 8 9 // Add geocache billboard entities to scene and style them if (Cesium.defined(entity.billboard)) { // Adjust the vertical origin so pins sit on terrain entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; // Disable the labels to reduce clutter entity.label = undefined; // Add distance display condition entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0); } For more help on distanceDisplayCondition, see the sandcastle example.\nNext, let\u0026rsquo;s improve the Infobox for each geocache entity. The Infobox title is the entity name, and the content is the entity description, displayed as HTML.\nYou\u0026rsquo;ll notice the default description isn\u0026rsquo;t very helpful. Since we\u0026rsquo;re displaying geocache locations, let\u0026rsquo;s update them to show the longitude and latitude of each point.\nFirst, we convert the entity\u0026rsquo;s position to cartographic, then read the longitude and latitude from the Cartographic and add them to the description in an HTML table.\nWhen clicked, our geocache entities will now display a well-formatted Infobox with just the data we need.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // Add geocache billboard entities to scene and style them if (Cesium.defined(entity.billboard)) { // Adjust the vertical origin so pins sit on terrain entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; // Disable the labels to reduce clutter entity.label = undefined; // Add distance display condition entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0); // Compute longitude and latitude in degrees var cartographicPosition = Cesium.Cartographic.fromCartesian(entity.position.getValue(Cesium.JulianDate.now())); var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude); var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude); // Modify description // Modify description var description = \u0026#39;\u0026lt;table class=\u0026#34;cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter\u0026#34;\u0026gt;\u0026lt;tbody\u0026gt;\u0026#39; + \u0026#39;\u0026lt;tr\u0026gt;\u0026lt;th\u0026gt;\u0026#39; + \u0026#34;Longitude\u0026#34; + \u0026#39;\u0026lt;/th\u0026gt;\u0026lt;td\u0026gt;\u0026#39; + longitude.toFixed(5) + \u0026#39;\u0026lt;/td\u0026gt;\u0026lt;/tr\u0026gt;\u0026#39; + \u0026#39;\u0026lt;tr\u0026gt;\u0026lt;th\u0026gt;\u0026#39; + \u0026#34;Latitude\u0026#34; + \u0026#39;\u0026lt;/th\u0026gt;\u0026lt;td\u0026gt;\u0026#39; + latitude.toFixed(5) + \u0026#39;\u0026lt;/td\u0026gt;\u0026lt;/tr\u0026gt;\u0026#39; + \u0026#39;\u0026lt;/tbody\u0026gt;\u0026lt;/table\u0026gt;\u0026#39;; entity.description = description; } Our geocache markers should now look like this:\nFor our geo application, it would also be helpful to visualize the neighborhoods of specific points. Let\u0026rsquo;s try loading a GeoJSON file containing polygons for each New York neighborhood. Loading GeoJSON files is very similar to the loading process we just used for KML. But in this case, we use GeoJsonDataSource. Like the previous data source, we need to add it to viewer.dataSources to actually add the data to the scene.\n1 2 3 4 5 6 7 8 9 10 11 12 var geojsonOptions = { clampToGround : true }; // Load neighborhood boundaries from KML file var neighborhoodsPromise = Cesium.GeoJsonDataSource.load(\u0026#39;./Source/SampleData/neighborhoods.geojson\u0026#39;, geojsonOptions); // Save an new entity collection of neighborhood data var neighborhoods; neighborhoodsPromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); }); Let\u0026rsquo;s adjust the loaded neighborhood polygons. Just like the billboard styling we just did, we first iterate through the neighborhood data source entities after the data source loads, this time checking if each entity\u0026rsquo;s polygon is defined:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Save an new entity collection of neighborhood data var neighborhoods; neighborhoodsPromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); neighborhoods = dataSource.entities; // Get the array of entities var neighborhoodEntities = dataSource.entities.values; for (var i = 0; i \u0026lt; neighborhoodEntities.length; i++) { var entity = neighborhoodEntities[i]; if (Cesium.defined(entity.polygon)) { // entity styling code here } } }); Since we\u0026rsquo;re displaying neighborhoods, let\u0026rsquo;s rename each entity to use the neighborhood as its name. The neighborhood from the original GeoJSON file is stored as a property. Cesium stores GeoJSON properties in entity.properties, so we can set the neighborhood name like this:\n1 2 3 4 // entity styling code here // Use geojson neighborhood value as entity name entity.name = entity.properties.neighborhood; Instead of making all neighborhoods the same color, we can assign each polygon a new color material with a random color using ColorMaterialProperty and Color.\n1 2 3 4 5 6 7 8 9 10 11 12 // entity styling code here // Set the polygon material to a random, translucent color. entity.polygon.material = Cesium.Color.fromRandom({ red : 0.1, maximumGreen : 0.5, minimumBlue : 0.5, alpha : 0.6 }); // Tells the polygon to color the terrain. ClassificationType.CESIUM_3D_TILE will color the 3D tileset, and ClassificationType.BOTH will color both the 3d tiles and terrain (BOTH is the default) entity.polygon.classificationType = Cesium.ClassificationType.TERRAIN; Finally, let\u0026rsquo;s generate a Label with some basic styling options for each entity. To keep things clean, we can use disableDepthTestDistance to make Cesium always render the labels above any 3D objects that might occlude them.\nHowever, note that labels are always positioned at entity.position. A Polygon is created with an undefined position because it has a list of positions defining the polygon boundary. We can generate a position by taking the center of the polygon positions:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // entity styling code here // Generate Polygon position var polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions; var polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center; polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter); entity.position = polyCenter; // Generate labels entity.label = { text : entity.name, showBackground : true, scale : 0.6, horizontalOrigin : Cesium.HorizontalOrigin.CENTER, verticalOrigin : Cesium.VerticalOrigin.BOTTOM, distanceDisplayCondition : new Cesium.DistanceDisplayCondition(10.0, 8000.0), disableDepthTestDistance : 100.0 }; This gives us labeled polygons that look like this:\nFinally, let\u0026rsquo;s add a high-tech perspective to our NYC geocaches by adding a drone flight over the city.\nSince the flight path is just a series of positions over time, we can add this data from a CZML file. CZML is a format for describing time-dynamic graphical scenes, primarily for display in web browsers running Cesium. It describes lines, points, billboards, models, and other graphical primitives, and specifies how they change over time. CZML is to Cesium what KML is to Google Earth \u0026ndash; a standard format that allows most Cesium features to be used through a declarative styling language (in this case, a JSON schema).\nOur CZML file defines an entity (visualized as a point by default) whose position is defined as a series of positions at different time points. There are several property types available in the Entity API for handling time-dynamic data. See the demo example below:\nProperty Types Demo 1 2 3 4 5 6 // Load a drone flight path from a CZML file var dronePromise = Cesium.CzmlDataSource.load(\u0026#39;./Source/SampleData/SampleFlight.czml\u0026#39;); dronePromise.then(function(dataSource) { viewer.dataSources.add(dataSource); }); The CZML file uses Cesium to display a drone flight. The path is a property that shows the entity\u0026rsquo;s position over time. A path visualizes discrete points connected into a continuous line using interpolation. Finally, let\u0026rsquo;s improve the appearance of the drone flight. First, instead of simply displaying a point, we can load a 3D model to represent our drone and attach it to the entity.\n3D Model Demo 3D Model Coloring Demo Cesium supports loading 3D models based on glTF (GL Transmission Format), an open specification developed by the Cesium team together with the Khronos Group, designed to efficiently load 3D models for applications by minimizing file size and runtime processing. Don\u0026rsquo;t have a glTF model? We provide an online converter to convert COLLADA and OBJ files to glTF format.\nLet\u0026rsquo;s load a drone Model with nice physically-based shading and some animations:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 var drone; dronePromise.then(function(dataSource) { viewer.dataSources.add(dataSource); // Get the entity using the id defined in the CZML data drone = dataSource.entities.getById(\u0026#39;Aircraft/Aircraft1\u0026#39;); // Attach a 3D model drone.model = { uri : \u0026#39;./Source/SampleData/Models/CesiumDrone.gltf\u0026#39;, minimumPixelSize : 128, maximumScale : 1000, silhouetteColor : Cesium.Color.WHITE, silhouetteSize : 2 }; }); Now our model looks good, but unlike the original point, the drone model has a direction, and it looks strange when the drone moves forward without orientation. Fortunately, Cesium provides a VelocityOrientationProperty, which automatically calculates orientation based on positions sampled before and after the entity:\n1 2 // Add computed orientation based on sampled positions drone.orientation = new Cesium.VelocityOrientationProperty(drone.position); Now our drone model will behave as expected.\nOne more thing we can do to improve the appearance of our drone flight: from a distance, it may not be obvious, but the drone\u0026rsquo;s path is made up of line segments that look unnatural. This is because Cesium uses linear interpolation by default to construct the path from sampled points. However, interpolation options can be configured.\nInterpolation Demo For a smoother flight path, we can change the interpolation options like this:\n1 2 3 4 5 // Smooth path interpolation drone.position.setInterpolationOptions({ interpolationDegree : 3, interpolationAlgorithm : Cesium.HermitePolynomialApproximation }); Cesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/161.html | China fast access: http://cesium.coinidea.com/topic/161.html\n","date":"2018-08-15T07:42:41Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-9-loading-and-styling-entities/","title":"[CesiumJS]Cesium Getting Started 9 - Loading and Styling Entities"},{"content":"Next, we\u0026rsquo;ll add some more correct time and space settings to the Viewer. This involves interacting with viewer.scene, which controls all graphical elements in the viewer.\nFirst, let\u0026rsquo;s configure our scene by enabling lighting based on the sun\u0026rsquo;s position with the following code: 1 2 // Enable lighting based on sun/moon positions viewer.scene.globe.enableLighting = true; With this configuration, the lighting in our scene will change with the time of day. If you zoom out, you\u0026rsquo;ll see that part of the digital globe is in darkness, because like the real Earth, the sun can only illuminate part of it.\nBefore we initialize and start the view, let\u0026rsquo;s briefly go over some basic Cesium types: Cartesian3 : A 3D Cartesian coordinate \u0026ndash; when used as a position relative to the center of the Earth, it uses the Earth-Fixed reference frame (ECEF). Cartographic : A position defined by longitude, latitude (in radians), and height above the WGS84 ellipsoid surface. HeadingPitchRoll : A rotation (in radians) about the local axes in an east-north-up frame. Heading is a rotation about the negative Z axis. Pitch is a rotation about the negative Y axis. Roll is a rotation about the positive X axis. Quaternion : A 3D rotation represented as a 4D coordinate. These are the basic types needed to position and orient Cesium objects in the scene, and they have many useful conversion methods. See the documentation for each type to learn more.\nNow let\u0026rsquo;s position the camera on the NYC (New York) scene where our data is located.\nCamera Control The camera is a property of viewer.scene that controls the currently visible domain. We can control the camera by directly setting its position and orientation, or by using the API provided by Cesium, which is designed to specify how the camera\u0026rsquo;s position and orientation change over time.\nSome of the most commonly used methods are:\nCamera.setView(options): Immediately sets the camera at a specific position and orientation. Camera.zoomIn(amount): Moves the camera forward along the view vector. Camera.zoomOut(amount): Moves the camera backward along the view vector. Camera.flyTo(options): Creates an animated camera flight from the current position to a new position. Camera.lookAt(target, offset) : Positions and orients the camera to aim at a target point with a given offset. Camera.move(direction, amount) : Moves the camera in any direction. Camera.rotate(axis, angle) : Rotates the camera around any axis. For more API features, check out these camera demos:\nCamera API Demo Custom Camera Controls Demo Let\u0026rsquo;s try one method to fly the camera to New York. Use camera.setView() to initialize the view, specifying the camera position and orientation with Cartesian3 and HeadingPitchRoll:\n1 2 3 4 5 6 7 8 9 10 11 12 13 // Create an initial camera view var initialPosition = new Cesium.Cartesian3.fromDegrees(-73.998114468289017509, 40.674512895646692812, 2631.082799425431); var initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(7.1077496389876024807, -31.987223091598949054, 0.025883251314954971306); var homeCameraView = { destination : initialPosition, orientation : { heading : initialOrientation.heading, pitch : initialOrientation.pitch, roll : initialOrientation.roll } }; // Set the initial view viewer.scene.camera.setView(homeCameraView); The camera is now positioned and oriented to overlook Manhattan, and our view parameters are saved in an object that can be passed to other camera methods.\nIn fact, we can use this same view to update the behavior when the home button is pressed. Instead of having it return to the default view of the Earth from a distance, we can override the button to show our initial Manhattan view. We can add a few options to adjust the animation, then add an event listener to cancel the default flight and call flyTo() with our home view:\n1 2 3 4 5 6 7 8 9 10 // Add some camera flight animation options homeCameraView.duration = 2.0; homeCameraView.maximumHeight = 2000; homeCameraView.pitchAdjustHeight = 2000; homeCameraView.endTransform = Cesium.Matrix4.IDENTITY; // Override the default home button viewer.homeButton.viewModel.command.beforeExecute.addEventListener(function (e) { e.cancel = true; viewer.scene.camera.flyTo(homeCameraView); }); For more about basic camera control, please visit our Camera Tutorial.\nClock Control Next, let\u0026rsquo;s configure the Viewer\u0026rsquo;s Clock and Timeline to control the scene\u0026rsquo;s time progression.\nHere is the Clock-related API.\nWhen working with specific times, Cesium uses the JulianDate type, which stores the number of days since noon on January 1, -4712 (4713 BC). For increased precision, this class stores the whole number of days and seconds in separate components. For computational safety and to represent leap seconds, dates are always stored in the International Atomic Time standard.\nHere is an example of how to set up scene time options:\n1 2 3 4 5 6 7 8 9 // Set up clock and timeline. viewer.clock.shouldAnimate = true; // make the animation play when the viewer starts viewer.clock.startTime = Cesium.JulianDate.fromIso8601(\u0026#34;2017-07-11T16:00:00Z\u0026#34;); viewer.clock.stopTime = Cesium.JulianDate.fromIso8601(\u0026#34;2017-07-11T16:20:00Z\u0026#34;); viewer.clock.currentTime = Cesium.JulianDate.fromIso8601(\u0026#34;2017-07-11T16:00:00Z\u0026#34;); viewer.clock.multiplier = 2; // sets a speedup viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER; // tick computation mode viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // loop at the end viewer.timeline.zoomTo(viewer.clock.startTime, viewer.clock.stopTime); // set visible range This sets the scene animation\u0026rsquo;s rate, start and stop times, and tells the clock to loop back to the start when it reaches the stop time. It also sets the timeline control to the appropriate time range. Check out this clock sample code to test clock settings.\nThis is our initial scene configuration! Now, when you run your application, you should see the following: Cesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/160.html | China fast access: http://cesium.coinidea.com/topic/160.html\n","date":"2018-08-15T07:30:05Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-8-configuring-the-scene/","title":"[CesiumJS]Cesium Getting Started 8 - Configuring the Scene"},{"content":"Cesium supports streaming, visualizable global elevation terrain data, including oceans, lakes, rivers, mountains, canyons, and other terrain data that can be rendered in 3D with better results than 2D. Like imagery data, the Cesium engine requests streaming terrain data from a server, only requesting data for the layers that need to be rendered based on the current camera view.\nCesium provides some terrain dataset examples and how to configure these parameters:\nArcticDEM : High-resolution arctic terrain PAMAP Terrain : High-resolution Pennsylvania terrain Terrain display options : Various terrain data configurations and formats Terrain exaggeration : Makes height differences between terrain more visually prominent Supported terrain data formats\nQuantized-mesh, an open-source format developed by the Cesium team Heightmap Google Earth Enterprise To add terrain data, we need to create a CesiumTerrainProvider, provide a URL and some configuration options, and then assign this provider to viewer.terrainProvider.\nHere, we use Cesium World Terrain, which is provided by Cesium ion and is available by default in \u0026ldquo;My Assets\u0026rdquo;. We can create a Cesium World Terrain served by Cesium ion using the createWorldTerrain helper function.\n1 2 3 4 5 // Load Cesium World Terrain viewer.terrainProvider = Cesium.createWorldTerrain({ requestWaterMask : true, // required for water effects requestVertexNormals : true // required for terrain lighting }); requestWaterMask and requestVertexNormals are optional configuration items that tell Cesium whether to request additional water and lighting data. Both options are set to false by default.\nFinally, since we now have terrain data, we need more lines to ensure that objects behind the terrain are displayed correctly \u0026ndash; only the frontmost, topmost objects should be visible.\n1 2 // Enable depth testing so things behind the terrain disappear. viewer.scene.globe.depthTestAgainstTerrain = true; We now have terrain data and moving water. New York is very flat, so you can freely explore the terrain data above. For a more obvious example, you can navigate to more rugged areas like the Grand Canyon or San Francisco.\nFor more information about terrain data, please visit the Terrain Tutorial\nCesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/157.html | China fast access: http://cesium.coinidea.com/topic/157.html\n","date":"2018-08-14T08:34:50Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-7-adding-terrain/","title":"[CesiumJS]Cesium Getting Started 7 - Adding Terrain"},{"content":"Another key element of a Cesium application is Imagery. Tile map collections are mapped onto the virtual 3D digital globe surface based on different projection methods. Depending on the camera\u0026rsquo;s direction and distance to the surface, Cesium requests and renders different levels of imagery detail.\nMultiple imagery layers can be added, removed, sorted, and adapted in Cesium.\nCesium provides a series of methods for handling imagery, such as color adaptation and layer blending. Here are some sample code examples:\nAdding basic imagery Adjusting imagery colors Manipulating and ordering imagery layers Splitting imagery layers Cesium provides various interfaces to support different imagery data sources.\nSupported imagery formats\nWMS TMS WMTS (with time dynamic imagery) ArcGIS Bing Maps Google Earth Mapbox OpenStreetMap Note: Different data sources require different authentication - make sure you have permission to access these data sources. Naturally, you\u0026rsquo;ll need to register for specific credentials.\nBy default, Cesium uses Bing Maps as the default imagery. This imagery is packaged into the Viewer for demonstration purposes. Cesium requires you to create your own ion account and generate an access key to access imagery data.\nIn the following example, we\u0026rsquo;ll use Sentinel-2 imagery from Cesium ion.\nGo to the Cesium ion page and add Sentinel-2 imagery to your assets. Click \u0026ldquo;Asset Depot\u0026rdquo; in the navigation bar. Click \u0026ldquo;Add to my assets\u0026rdquo;. Sentinel-2 will appear in your personal Asset list (My Assets), making the imagery data source available in your personal app.\nAt the code level: we create an IonImageryProvider and pass the assetId for the corresponding Sentinel-2 imagery. Then we add the ImageryProvider to viewer.imageryLayers.\n1 2 3 4 5 // Remove default base layer viewer.imageryLayers.remove(viewer.imageryLayers.get(0)); // Add Sentinel-2 imagery viewer.imageryLayers.addImageryProvider(new Cesium.IonImageryProvider({ assetId : 3954 })); Based on the above code, our Cesium application will show the following imagery when zooming in: For more information about imagery, please visit the Imagery Layers Tutorial\nCesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/156.html | China fast access: http://cesium.coinidea.com/topic/156.html\n","date":"2018-08-14T08:29:46Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-6-adding-imagery/","title":"[CesiumJS]Cesium Getting Started 6 - Adding Imagery"},{"content":"Cesium ion is a platform that provides tiled maps and 3D geospatial data. Cesium ion supports adding data to your own CesiumJS applications. Below we will use Sentinel-2 2D imagery and Cesium World Terrain, both of which require ion support.\nNote When using Cesium, if you haven\u0026rsquo;t applied for an ion account and are using Cesium\u0026rsquo;s default data sources instead of your own, the bottom of the viewer will often display a line of small English text. The message basically says you need to apply for an access token.\nFirst, you need to register for a free Cesium ion account. Go to https://cesium.com/ion/ and register a new account. Click \u0026ldquo;Access Token\u0026rdquo; to navigate to the Access Tokens page. Select the Default access token and copy the contents. When creating a Cesium Viewer, simply set the access token to your own:\n1 Cesium.Ion.defaultAccessToken = \u0026#39;\u0026lt;YOUR ACCESS TOKEN HERE\u0026gt;\u0026#39;; With this, you can freely access various data sources provided by Cesium ion.\nMore questions can be found at Getting Started with Cesium ion\nCesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/153.html | China fast access: http://cesium.coinidea.com/topic/153.html\n","date":"2018-08-13T07:43:34Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-5-cesium-ion/","title":"[CesiumJS]Cesium Getting Started 5 - Cesium ion"},{"content":"The foundation of any Cesium application is the Viewer. The Viewer is an interactive 3D digital globe container (box) with various features. To create a Viewer, simply bindg it to a div element with the id \u0026ldquo;cesiumContainer\u0026rdquo; in HTML.\n1 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); After using the code above, you can see the basic digital globe shown in the image below:\nBy default, the scene supports mouse (desktop) and touch (mobile device) interaction. You can control the camera to navigate the digital globe in the following ways:\nLeft click and drag - Pans the camera over the surface of the globe. Right click and drag - Zooms the camera in and out. Middle wheel scrolling - Also zooms the camera in and out. Middle click and drag - Rotates the camera around the point on the surface of the globe. The default Viewer comes with several useful widgets:\nGeocoder : A location search tool that flies the camera to queried location. Uses Bing Maps data by default. HomeButton : Flies the viewer back to a default view. SceneModePicker : Switches between 3D, 2D and Columbus View (CV) modes. BaseLayerPicker : Chooses the imagery and terrain to display on the globe. NavigationHelpButton : Displays the default camera controls. Animation : Controls the play speed for view animation. CreditsDisplay : Displays data attributions. Almost always required! Timeline : Indicates current time and allows users to jump to a specific time using the scrubber. FullscreenButton : Makes the Viewer fullscreen. We can configure the Viewer widgets through code by adding/removing related components via configuration parameters when initializing the Viewer. The following code creates a Viewer configured without the selection indicator, base layer picker, or scene mode picker components:\n1 2 3 4 5 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;, { scene3DOnly: true, selectionIndicator: false, baseLayerPicker: false }); For the complete Viewer configuration, please visit: https://cesiumjs.org/Cesium/Build/Documentation/Viewer.html.\nCesium Chinese Community QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/152.html | China fast access: http://cesium.coinidea.com/topic/152.html\n","date":"2018-08-13T06:55:35Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-4-creating-a-cesium-viewer/","title":"[CesiumJS]Cesium Getting Started 4 - Creating a Cesium Viewer"},{"content":"App Directory After downloading the files from the official website, we can see the following CesiumJS library structure:\nSource/: Cesium application code and data ThirdParty/: External dependency libraries, third-party libraries separate from Cesium LICENSE.md: Cesium license information index.html: Web homepage, which needs to be defined according to Cesium requirements and include Cesium dependency libraries server.js: Node.js-based web server application Note\nCesiumJS is adapted to work with third-party JavaScript libraries and frameworks:\nReact: Integrating Cesium with React\nThreeJS: Integrating Cesium with ThreeJS\nPage Structure Including CesiumJS 1 \u0026lt;script src=\u0026#34;ThirdParty/Cesium/Cesium.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; Developers can also pick and choose their dependency libraries from ThirdParty/Cesium/source/ according to their needs, trimming the JS file size.\nHTML Structure A div is needed as the container for the Cesium Viewer widget:\n1 \u0026lt;div id=\u0026#34;cesiumContainer\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; An app.js file is needed to activate the Cesium Viewer. It\u0026rsquo;s best to include app.js at the end of the HTML:\n1 \u0026lt;script src=\u0026#34;Source/App.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; Adding CSS Styles The styles for various widgets in the Cesium viewer need to be imported. Create a new index.css and include it in index.html:\n1 \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;index.css\u0026#34; media=\u0026#34;screen\u0026#34;\u0026gt; Add the following default Cesium CSS to index.css:\n1 @import url(ThirdParty/Cesium/Widgets/widgets.css); Steps Open Source/App.js and delete its contents Copy Source/AppSkeleton.js to Source/App.js Make sure server.js is in the Cesium root directory and run server.js (npm server.js) Enter localhost:8080 in a modern browser (with WebGL support) If you have any issues:\nFull code: https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/index.html?src=Hello%20World.html\u0026label=Showcases\u0026gist=8d9d3daadd197cffd501d7210bcca3b6\nRecommended code: https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/index.html?src=Hello%20World.html\u0026label=Showcases\u0026gist=113c3467755fc38d9f9bce16a94475fc\nCesium Chinese Website QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/144.html | Quick access: http://cesium.coinidea.com/topic/144.html\n","date":"2018-08-10T09:13:46Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-3-cesium-directory-and-framework-structure/","title":"[CesiumJS]Cesium Getting Started 3 – Cesium Directory and Framework Structure"},{"content":"Verify Browser Support Cesium requires browser support for WebGL. You can test whether your browser supports Cesium using a HelloWorld example provided on the CesiumJS official website. (Chrome is recommended) Test URL: https://cesiumjs.org/Cesium/Apps/HelloWorld.html\nChoose an IDE The official website states:\n1 If you\u0026#39;re already a seasoned developer, you most likely have a favorite editor or development environment; for example, most of the Cesium team uses Eclipse. If you\u0026#39;re just starting out, a great free and open-source editor is Notepad++, which you can download from their website. Ultimately any text editor will do, so go with the one that you are most comfortable with. If you\u0026rsquo;re already an experienced developer, you likely have a preferred editor or development environment; for example, most of the Cesium team uses Eclipse. If you\u0026rsquo;re just starting out, Notepad++ is a great free and open-source editor that you can download from their website. Ultimately, any text editor will work, so use whatever you\u0026rsquo;re most comfortable with.\nPersonally, since I mostly developed in PHP before, I use PHPStorm. I actually don\u0026rsquo;t recommend Eclipse — I prefer WebStorm, which shares the same parent as IntelliJ IDEA. Considering project and folder management, I also don\u0026rsquo;t recommend Notepad++. For a lightweight IDE, I recommend Sublime Text.\nDownload Cesium Source Code Download the latest release version at: https://cesiumjs.org/tutorials/cesium-up-and-running/\nAfter downloading, extract the zip file into a new directory of your choice. I\u0026rsquo;ll refer to this as the Cesium root directory throughout this tutorial. The contents should look like the following:\nSimply opening index.html directly won\u0026rsquo;t work — it needs to be placed in a web server container to run.\nServer Side Cesium is pure frontend code. The official source code comes with a Node.js server, and you can install and deploy via Node.js. In practice, Cesium can be deployed in Tomcat (GeoServer), Apache, Nginx, and other servers.\nThe official recommendation is Node.js:\nDownload Node.js from the official website (https://nodejs.org/en/). Node.js has some configurable parameters, but the defaults are fine. In the Cesium directory, open cmd or bash and run: 1 npm install This downloads the required npm modules such as express. If successful, a \u0026rsquo;node_modules\u0026rsquo; folder will be created in the Cesium directory. 3.\tFinally, run in cmd or bash: shell node server.js or shell npm start After success, you should see the following screenshot: The console will display:\n1 Cesium development server running locally. Connect to http://localhost:8080 Note: Do not close the console — keep it running. Open your browser and navigate to http://localhost:8080 to access Cesium.\nIf You Don\u0026rsquo;t Want to Use Node.js Cesium is an open-source project. The GitHub download URL is: https://github.com/AnalyticalGraphicsInc/cesium The simplest installation method is regular JS file loading — just download the JS code from GitHub, place it in your project, and reference it in your HTML page. Like this: Create a new helloworld.html:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Hello 3D Earth\u0026lt;/title\u0026gt; \u0026lt;script src=\u0026#34;CesiumUnminified/Cesium.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;style\u0026gt; @import url(CesiumUnminified/Widgets/widgets.css); html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } \u0026lt;/style\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div id=\u0026#34;cesiumContainer\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script src=\u0026#34;app.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Create a new app.js:\n1 viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); Here, cesiumContainer is the id of the HTML div that displays the map. It\u0026rsquo;s that simple — open the HTML page in a browser and you\u0026rsquo;ll see a 3D globe. The base map is Microsoft imagery loaded onto the 3D globe, with basic online map features including zoom in, zoom out, and pan. It also includes a timeline and other time-related widgets, which is a distinctive feature of Cesium — its maps, objects, and scenes can all be associated with time.\nLocal Hello World Program Now that the local Node server is running, open your browser and navigate to: http://localhost:8080/Apps/HelloWorld.html. You should see a Hello World 3D digital globe identical to the official one. Hello World Code Analysis The official Hello World code is as follows:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;!-- Use correct character set. --\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; \u0026lt;!-- Tell IE to use the latest, best version. --\u0026gt; \u0026lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=edge\u0026#34;\u0026gt; \u0026lt;!-- Make the application on mobile take up the full browser screen and disable user scaling. --\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Hello World!\u0026lt;/title\u0026gt; \u0026lt;script src=\u0026#34;../Build/Cesium/Cesium.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;style\u0026gt; @import url(../Build/Cesium/Widgets/widgets.css); html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } \u0026lt;/style\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div id=\u0026#34;cesiumContainer\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script\u0026gt; var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); \u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; The following four steps add Cesium to the HTML:\nInclude Cesium.js, which defines the Cesium object: 1 \u0026lt;script src=\u0026#34;../Build/Cesium/Cesium.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; Import the Cesium Viewer widget styles: 1 @import url(../Build/Cesium/Widgets/widgets.css); The Cesium view resides in this div: 1 \u0026lt;div id=\u0026#34;cesiumContainer\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; Finally, create the Cesium viewer: 1 var viewer = new Cesium.Viewer(\u0026#39;cesiumContainer\u0026#39;); Cesium Chinese Website QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/138.html | Quick access: http://cesium.coinidea.com/topic/137.html\n","date":"2018-08-10T03:11:34Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-2-environment-setup-and-first-example-program/","title":"[CesiumJS]Cesium Getting Started 2 – Environment Setup and First Example Program"},{"content":"Introduction to Cesium Cesium official website: https://cesiumjs.org The website title states:\n1 An open-source JavaScript library for world-class 3D globes and maps Cesium is an open-source JavaScript-based 3D mapping framework. Essentially, it is a map visualization framework.\nThe website description states:\n1 CesiumJS is a geospatial 3D mapping platform for creating virtual globes. Our mission is to create the leading web-based globe and map for visualizing dynamic data. We strive for the best possible performance, precision, visual quality, ease of use, platform support, and content. CesiumJS is a 3D geospatial platform for creating virtual scenes. Its goal is to create web-based dynamic data visualization using maps. It strives to provide the best performance, accuracy, visualization capabilities, ease of use, and platform support.\nData Formats and Features Cesium supports 3D Tiles, Terrain and Imagery Layers, 3D Models (glTF), Vectors and Geometry (Load KML, GeoJSON, TopoJSON, and CZML), Time-Dynamic Visualization, 3D, 2D, and 2.5D Columbus View.\nSupports 2D, 2.5D, and 3D geographic (map) data display Can draw various geometric shapes, highlight regions, supports importing images and even 3D models for diverse data visualization Can be used for dynamic data visualization with good touch support, compatible with most desktop and mobile browsers Supports time-axis-based dynamic streaming data display Thoughts Thanks to the development of frontend technologies, the standardization of HTML5 and CSS3, increasingly better WebGL support from major browser vendors, growing personal computer memory, and advances in graphics cards, I can see the browser-based 3D digital globe that I\u0026rsquo;ve always wanted to build becoming a reality. I\u0026rsquo;m very excited.\nSummary Cesium is a cross-platform, cross-browser JavaScript library for displaying 3D globes and maps. Cesium uses WebGL for hardware-accelerated graphics. No plugins are required, but the browser must support WebGL. Cesium is an open-source project licensed under Apache 2.0. It can be used freely for both commercial and non-commercial purposes. Cesium Chinese Website QQ Group: 807482793\nOriginal link: http://cesiumcn.org/topic/137.html | Quick access: http://cesium.coinidea.com/topic/137.html\n","date":"2018-08-09T03:28:08Z","permalink":"https://blog.coinidea.com/en/p/cesiumjscesium-getting-started-1-introduction-to-cesium/","title":"[CesiumJS]Cesium Getting Started 1 – Introduction to Cesium"},{"content":"Sharing some code to make the Cesium globe rotate automatically.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 var i = Date.now(); function rotate() { var a = .1; var t = Date.now(); var n = (t - i) / 1e3; i = t; viewer.scene.camera.rotate(Cesium.Cartesian3.UNIT_Z, -a * n); } viewer.clock.onTick.addEventListener(rotate); setTimeout(function() { viewer.clock.onTick.removeEventListener(rotate); }, 5000); ","date":"2018-07-26T07:48:41Z","permalink":"https://blog.coinidea.com/en/p/cesiumjssample-code-for-cesium-globe-rotation/","title":"[CesiumJS]Sample Code for Cesium Globe Rotation"},{"content":"Cesium does not support loading oblique photography OSGB data directly:\nhttps://www.oschina.net/question/104733_2198017\nHowever, OSGB data can be converted into a format that Cesium can load.\nCurrently, the best-supported format defined by Cesium is 3D Tiles. This format is still evolving and not yet fully mature, but based on official demos, the results are quite impressive.\n3D Tiles adds FeatureTable and BatchTable at the logical (JSON) layer, as well as the LOD (tileset) concept, with corresponding binary storage headers. From a data specification perspective, it inherits the excellent parts of glTF while also considering oblique photography and point clouds. Support for OSM is planned for the future, providing good coverage of data types.\n3D Tiles = glTF + LOD\nhttps://www.cnblogs.com/fuckgiser/p/6565957.html\nDuring development, I found some conversion tools shared by developers online:\nhttps://www.v2ex.com/t/402321\nhttps://blog.csdn.net/qq_37796475/article/details/79221939\nAfter testing, I found that:\nhttps://download.csdn.net/download/qq_37796475/10274378 this tool works quite well.\nAfter downloading the conversion tool, there is an operation example image included in the directory. Feel free to leave a comment if you have any questions.\nOriginal link: http://cesiumcn.org/topic/3.html\n","date":"2018-07-26T07:44:58Z","permalink":"https://blog.coinidea.com/en/p/cesiumjsosgb-to-cesium-3d-tiles-conversion-tool/","title":"[CesiumJS]OSGB to Cesium 3D Tiles Conversion Tool"},{"content":"Official API:\nYou can download the official PHP ElasticSearch API and read the documentation for related operations.\nExample code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static public function initSearchClient() { if (null == BaseFrontController::$client) { $hosts[\u0026#39;hosts\u0026#39;] = array( \u0026#34;host\u0026#34; =\u0026gt; \u0026#39;127.0.0.1\u0026#39;, \u0026#34;port\u0026#34; =\u0026gt; \u0026#39;9200\u0026#39;, \u0026#39;scheme\u0026#39; =\u0026gt; \u0026#39;http\u0026#39; ); BaseFrontController::$client = \\Elasticsearch\\ClientBuilder::create() -\u0026gt;setSSLVerification(false) -\u0026gt;setHosts($hosts) -\u0026gt;build(); } } // Elastic search static public function actionSearch($area, $keyword, $start, $end, $size=100, $agg = null) { BaseFrontController::initSearchClient(); $params[\u0026#39;index\u0026#39;] = BaseFrontController::getSearchIndex(); $params[\u0026#39;type\u0026#39;] = \u0026#39;raw\u0026#39;; $params[\u0026#39;body\u0026#39;][\u0026#34;size\u0026#34;] = $size; // your aggs if (null != $agg) { $params[\u0026#39;body\u0026#39;][\u0026#34;aggs\u0026#34;] = $agg; } $params[\u0026#39;body\u0026#39;][\u0026#34;query\u0026#34;][\u0026#34;filtered\u0026#34;][\u0026#39;filter\u0026#39;][\u0026#34;and\u0026#34;] = [ [\u0026#34;term\u0026#34;=\u0026gt;[\u0026#39;Your area\u0026#39; =\u0026gt; $area]], // your area [\u0026#34;range\u0026#34;=\u0026gt;[\u0026#34;Your time\u0026#34; =\u0026gt; array(\u0026#34;gte\u0026#34;=\u0026gt;$start, \u0026#34;lte\u0026#34;=\u0026gt;$end)]] // your time ]; if ($keyword != \u0026#39;\u0026#39;) { $params[\u0026#39;body\u0026#39;][\u0026#34;query\u0026#34;][\u0026#34;filtered\u0026#34;][\u0026#39;query\u0026#39;][\u0026#39;bool\u0026#39;][\u0026#39;should\u0026#39;][\u0026#39;match_phrase\u0026#39;] = array();// your query word } $response = BaseFrontController::$client-\u0026gt;search($params); return $response; } ","date":"2018-01-04T09:04:18Z","permalink":"https://blog.coinidea.com/en/p/elasticsearchphp-operations-with-elasticsearch/","title":"[ElasticSearch]PHP Operations with ElasticSearch"},{"content":" 1 2 3 4 5 6 7 8 9 10 if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(getPosition, getPositionError, { // Indicates the browser should obtain high-accuracy position, default is false enableHighAccuracy: true, // Specifies the timeout for obtaining geolocation, default is unlimited, in milliseconds timeout: 5000, // Maximum cache age — when repeatedly obtaining geolocation, this parameter specifies how long before re-fetching the position maximumAge: 3000 }); } The above code is commonly seen in H5-related geolocation implementations. It uses the device\u0026rsquo;s own GPS for positioning, but through testing I found it was very inaccurate. The desktop version would directly throw errors.\nOn mobile, if you use Baidu\u0026rsquo;s API set, the location drifts significantly. Based on observation, it uses cell tower positioning. I then thought — is Baidu really this bad? So I tried the native code above, and found it frequently errors out:\nError using Geolocation method: error.POSITION_UNAVAILABLE\nAfter investigating for a long time, the desktop version just wouldn\u0026rsquo;t work. Finally I figured it out — key point: GPS services now strongly prefer HTTPS. HTTP is increasingly unsupported. Chrome even explicitly states that geolocation requires HTTPS.\nAfter testing again with HTTPS, the accuracy was incredible — within 10 meters.\n","date":"2018-01-04T07:54:52Z","permalink":"https://blog.coinidea.com/en/p/web-developmenthtml5-geolocation-inaccuracy-issues/","title":"[Web Development]HTML5 Geolocation Inaccuracy Issues"},{"content":"Time flies, and 2017 has finally come to an end. To be honest, I have some mixed feelings about writing summaries.\n1. Technology: 1. Frontend Tech Stack: 1.1 Went through VUE once and basically got started with it;\n1.2 Had some exposure to Fis3;\n2. PHP Related: 2.1 Learned Yii 2.0 and implemented some simple projects;\n2.2 Upgraded from ThinkPHP 3.x to ThinkPHP 5;\n3. Algorithm Related: 3.1 During the middle of the year, I solved several dozen LeetCode problems, but didn\u0026rsquo;t keep it up. Back in 2015 I should have finished them all, but now there are many new problems. I also picked up STL, Vector, etc. again.\n3.2 The proudest achievement this year was working with OpenCV, implementing a BOW image classification algorithm, and also using OpenCV-based decision trees, SVM, etc.\n4. System Related: 4.1 I had already gone through CDH back in 2015. The most rewarding thing this year was getting ElasticSearch up and running with approximately 150 million records, including tokenization, mapping, indexing, and aggregation. Going through this whole process was very fulfilling.\n2. Travel: I\u0026rsquo;m a bit embarrassed to say — including business trips, I only went to Shanghai, Nanjing, and Qingdao. Just these three cities. But I finally made it to Shanghai Disneyland, which was nice, just way too crowded.\n3. Coinidea: Did it take off? I don\u0026rsquo;t think so. It didn\u0026rsquo;t go particularly well. I\u0026rsquo;ve built dozens of websites, WebApps, and APIs of various sizes, but I feel very lost and don\u0026rsquo;t know which direction to take next. I\u0026rsquo;ve been making some attempts recently and hope that new doors will open for me.\nHopes for Next Year Android — I studied it before but never followed through. Develop and publish a WeChat Mini Program. Study and learn PostgreSQL. Further study data mining and deep learning algorithms. That\u0026rsquo;s it, no grand wishes. Setting low goals is good for everyone :)\n","date":"2018-01-04T07:25:24Z","permalink":"https://blog.coinidea.com/en/p/year-end-reviewmy-2017/","title":"[Year-End Review]My 2017"},{"content":"Create the backup.sh Script Create a new backup.sh file with the following content:\n1 2 3 4 5 6 7 8 9 10 11 12 db_user=\u0026#34;Your database user\u0026#34; db_passwd=\u0026#34;Your password\u0026#34; db_name=\u0026#34;Your database name\u0026#34; # Backup file storage directory — you need to change this directory backup_dir=\u0026#34;/home/mysqlbackup\u0026#34; # Date format for backup files (dd-mm-yyyy) time=\u0026#34;$(date +\u0026#34;%Y%m%d%H%M%S\u0026#34;)\u0026#34; # Execute the backup command mysqldump -h localhost -u $db_user -p$db_passwd --all-databases --sock=/var/lib/mysql/mysql.sock \u0026gt; \u0026#34;$backup_dir/db_$time.sql\u0026#34; Then, grant execution permissions and run the script:\n1 2 chmod +x ./backup.sh bash -x ./backup.sh If you get a socket error, you need to specify sock. See: http://blog.csdn.net/seteor/article/details/18356079.\nCreate a Scheduled Task Edit the crontab:\n1 crontab -e In the editor, add the following line:\n1 00 23 * * * /home/mysqlbackup/backup.sh This command will execute backup.sh every day at 23:00, backing up the database to /home/mysqlbackup.\nView scheduled tasks:\n1 crontab -l ","date":"2017-11-28T02:59:06Z","permalink":"https://blog.coinidea.com/en/p/mysqlautomatic-mysql-backup/","title":"[MySQL]Automatic MySQL Backup"},{"content":"Upgrading OpenSSH to Version 7.4 or Above Background Currently, OpenSSH versions below 7.4 on Linux have some critical vulnerabilities, and OpenSSH needs to be upgraded to version 7.4 or above. On a machine without external network access (no yum), this is quite troublesome. Online resources generally recommend backing up SSH and installing Telnet first, so you can still access the machine via Telnet if the upgrade fails.\nCommon Issues and Solutions 1. Cannot find zlib.h Reference: http://www.linuxidc.com/Linux/2012-10/72036.htm\n2. zlib download link http://www.zlib.net/ 3. Installing zlib Reference: http://www.360doc.com/content/13/0124/17/1200324_262179628.shtml\n4. Dependencies required for manually compiling OpenSSH zlib pam pam-devel If you get the error configure: error: PAM headers not found, you can download pam-devel:\nhttp://rpm.pbone.net/index.php3?stat=26\u0026amp;dist=74\u0026amp;size=208492\u0026amp;name=pam-devel-1.1.1-17.el6.x86_64.rpm 5. OpenSSL download ftp://ftp.openssl.org/source/ 6. Installing OpenSSL References:\nhttp://blog.csdn.net/ikownyou/article/details/53021686 http://www.linuxidc.com/Linux/2011-10/45738.htm Notes If SecureCRT cannot log in after upgrading OpenSSH, it may be because the SecureCRT version is too old to support certain encryption protocols:\nReference: http://blog.csdn.net/yangg1991/article/details/51755562\nSteps to Upgrade OpenSSH Reference: http://blog.csdn.net/u011080082/article/details/64503534\nUpgrading vsftpd from 2.2.2 to 2.3.4 Download the vsftpd-2.3.4.tar.gz package. For 64-bit systems, note:\n1 2 sed -i \u0026#39;s/lib\\/lib64\\/g\u0026#39; vsf_findlibs.sh sed -i \u0026#39;s/lib\\//lib64\\//g\u0026#39; vsf_findlibs.sh Configuring vsftpd Using active mode:\n1 vsftpd /etc/vsftpd/vsftpd.conf \u0026amp; When starting in standard_alone mode, you need to add the following two lines to the top of the configuration file:\nReference: http://wingjang.blog.163.com/blog/static/47913442200811113104509/\n1 2 listen=YES listen_port=21 After installation, only anonymous users are allowed to log in by default, so you need to modify the configuration:\nReference: http://blog.sina.com.cn/s/blog_7e16680c01018ox1.html\nHandling TCP_Wrapper Issues If there are issues, pay attention to removing spaces, or you can remove it entirely:\nReferences:\nhttp://blog.csdn.net/u010098331/article/details/50699914 http://blog.csdn.net/yylklshmyt20090217/article/details/8500608 vsftpd Download http://pkgs.fedoraproject.org/repo/pkgs/vsftpd/ ","date":"2017-11-23T08:05:04Z","permalink":"https://blog.coinidea.com/en/p/centosupgrading-openssh-and-vsftpd-on-centos/","title":"[CentOS]Upgrading OpenSSH and vsftpd on CentOS"},{"content":"Having used MySQL-like databases for so long, one day I ran into a major pitfall with ES.\nWhen posting the mapping, I didn\u0026rsquo;t properly distinguish between \u0026ldquo;analyzed\u0026rdquo; and \u0026ldquo;not_analyzed\u0026rdquo; for a field, which accidentally caused all data in that column to be tokenized. The dataset had approximately 150 million records.\nI naively thought I could just modify the field attributes like in MySQL. ES is based on Lucene, and there\u0026rsquo;s no other way — in simple terms, you either delete the index and re-import, or reindex. Reindexing means creating a new index and copying the data from the old index over. There are many tutorials online for this, for example:\nhttp://blog.csdn.net/loveyaqin1990/article/details/77684599\nhttps://www.cnblogs.com/wmx3ng/p/4112993.html\nAs for actual implementation code, there\u0026rsquo;s very little available online. After a long search, I only found a Python implementation. This article provides a migration implementation based on the official ES PHP SDK and bulk API.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 \u0026lt;?php require \u0026#39;vendor/autoload.php\u0026#39;; $hosts[\u0026#39;hosts\u0026#39;] = array( \u0026#34;host\u0026#34; =\u0026gt; \u0026#39;127.0.0.1\u0026#39;, \u0026#34;port\u0026#34; =\u0026gt; \u0026#39;9200\u0026#39;, \u0026#39;scheme\u0026#39; =\u0026gt; \u0026#39;http\u0026#39; ); $client = Elasticsearch\\ClientBuilder::create() -\u0026gt;setSSLVerification(false) -\u0026gt;setHosts($hosts) -\u0026gt;build(); for ($i = 1; $i \u0026lt;= 10; $i++) { if ($i != 10) { $params[\u0026#39;index\u0026#39;] = \u0026#39;index-0\u0026#39;.$i; } else { $params[\u0026#39;index\u0026#39;] = \u0026#39;index-\u0026#39;.$i; } echo $params[\u0026#34;index\u0026#34;].\u0026#34;\\r\\n\u0026#34;; $params[\u0026#39;type\u0026#39;] = \u0026#39;raw\u0026#39;; $params[\u0026#39;scroll\u0026#39;] = \u0026#39;120s\u0026#39;; $params[\u0026#34;size\u0026#34;] = 50000; $params[\u0026#34;body\u0026#34;] = array( \u0026#34;query\u0026#34; =\u0026gt; array( \u0026#34;match_all\u0026#34; =\u0026gt; array() ) ); $response = $client-\u0026gt;search($params); $step = 1; while (isset($response[\u0026#39;hits\u0026#39;][\u0026#39;hits\u0026#39;]) \u0026amp;\u0026amp; count($response[\u0026#39;hits\u0026#39;][\u0026#39;hits\u0026#39;]) \u0026gt; 0) { echo $step++.\u0026#34;\\t\u0026#34;; $scroll_id = $response[\u0026#39;_scroll_id\u0026#39;]; unset($response); $response = $client-\u0026gt;scroll( array( \u0026#34;scroll_id\u0026#34; =\u0026gt; $scroll_id, \u0026#34;scroll\u0026#34; =\u0026gt; \u0026#34;120s\u0026#34; ) ); if (count($response[\u0026#39;hits\u0026#39;][\u0026#39;hits\u0026#39;]) \u0026gt; 0) { $bulk = array(\u0026#39;index\u0026#39;=\u0026gt;$params[\u0026#39;index\u0026#39;].\u0026#34;-reindex\u0026#34;,\u0026#39;type\u0026#39;=\u0026gt;$params[\u0026#39;type\u0026#39;]); foreach ($response[\u0026#34;hits\u0026#34;][\u0026#34;hits\u0026#34;] as $key=\u0026gt;$val) { $bulk[\u0026#39;body\u0026#39;][]=array( \u0026#39;index\u0026#39; =\u0026gt; array( \u0026#39;_id\u0026#39;=\u0026gt;$val[\u0026#39;_id\u0026#39;] ), ); $bulk[\u0026#39;body\u0026#39;][] = $val[\u0026#39;_source\u0026#39;]; } // insert reindex $res = $client-\u0026gt;bulk($bulk); unset($bulk); } else { break; } } } ?\u0026gt; ","date":"2017-11-19T12:23:18Z","permalink":"https://blog.coinidea.com/en/p/elasticsearchmodifying-es-mapping/","title":"[ElasticSearch]Modifying ES Mapping"},{"content":"When the server interacts with mobile clients, it often needs to push messages from the server to the user\u0026rsquo;s mobile device. Umeng provides such a push notification service — UPush.\nDownload the SDK code. Based on the demo, this article provides a simple ThinkPHP integration.\n1 2 3 4 5 6 $appkey = \u0026#34;your app key\u0026#34;; $secret = \u0026#34;your app secret\u0026#34;; import(\u0026#39;@.ORG.Notification\u0026#39;); $notification = new Notification($appkey, $secret); $custom_data = array($key=\u0026gt;$value); $notification-\u0026gt;sendIOSBroadcast($your_title, $custom_data); Notification.class.php is the demo.php from the SDK, encapsulated into ThinkPHP\u0026rsquo;s ORG folder.\nIf you have any questions, feel free to leave a comment below. I typically reply once a day.\n","date":"2017-11-19T11:48:10Z","permalink":"https://blog.coinidea.com/en/p/push-notificationspush-notifications-based-on-umeng-service/","title":"[Push Notifications]Push Notifications Based on Umeng Service"},{"content":"Recently I needed to build a registration system that doesn\u0026rsquo;t require very high concurrency, but there\u0026rsquo;s still a possibility of multiple users registering at the same time. Since registration involves ordering, without row locking or table locking, the following situation can occur.\nExample:\nCurrently the system only has user A registered with order 1, denoted as (A, 1).\nAt some moment t, users B, C, and D register simultaneously. The backend receives all three requests almost at the same time, queries the registration table, finds only (A, 1), and inserts (B, 2), (C, 2), (D, 2) into the table, resulting in:\n1 2 3 4 (A, 1) (B, 2) (C, 2) (D, 2) My initial idea was: instead of recording the order number, I would record the insertion timestamp, which would give:\n1 2 3 4 (A, ta) (B, tb) (C, tc) (D, td) ta, tb, tc, td are almost impossible to be equal.\nHowever, this approach has three unsolvable issues:\nThere is a (very low) probability that timestamps could be equal It\u0026rsquo;s not intuitive and requires sorting by timestamp Registration has a capacity limit (e.g., 40 spots) and needs to immediately report whether the registration was successful The current solution is to use database locking.\nAfter researching online, ThinkPHP supports both pessimistic and optimistic locking. Given the low traffic of the target system, pessimistic locking is sufficient.\nMyISAM can only lock tables, while InnoDB supports row-level locking. Table locking is sufficient for the target system.\nThe official documentation provides this table locking approach:\n1 $User-\u0026gt;lock(true)-\u0026gt;save($data);// Use pessimistic locking However, the target system needs to perform a series of operations, so the table locking code used is:\n1 2 3 4 M()-\u0026gt;query(\u0026#34;lock tables yourtable write\u0026#34;); // TODO // your code M()-\u0026gt;query(\u0026#34;unlock tables\u0026#34;); The actual results worked quite well [real dates have been redacted]:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ??-??-?? 10:00:00 1 ??-??-?? 10:00:00 2 ??-??-?? 10:00:00 3 ??-??-?? 10:00:00 4 ??-??-?? 10:00:01 5 ??-??-?? 10:00:01 6 ??-??-?? 10:00:01 7 ??-??-?? 10:00:01 8 ??-??-?? 10:00:02 9 ??-??-?? 10:00:02 10 ??-??-?? 10:00:02 11 ??-??-?? 10:00:02 12 ??-??-?? 10:00:02 13 ??-??-?? 10:00:02 14 ??-??-?? 10:00:03 15 ??-??-?? 10:00:03 16 ??-??-?? 10:00:03 17 ??-??-?? 10:00:05 18 ??-??-?? 10:00:06 19 ??-??-?? 10:00:07 20 ??-??-?? 10:00:08 21 ??-??-?? 10:00:10 22 ??-??-?? 10:00:15 23 ??-??-?? 10:00:17 24 ??-??-?? 10:00:19 25 ??-??-?? 10:00:19 26 ??-??-?? 10:00:24 27 ??-??-?? 10:00:25 28 ??-??-?? 10:00:34 29 ??-??-?? 10:00:35 30 ??-??-?? 10:00:38 31 ??-??-?? 10:01:06 32 ??-??-?? 10:01:11 33 ??-??-?? 10:01:11 34 ??-??-?? 10:01:17 35 ??-??-?? 10:01:18 36 ??-??-?? 10:02:27 37 ??-??-?? 10:02:38 38 ??-??-?? 10:02:39 39 ??-??-?? 10:02:57 40 ","date":"2017-11-17T03:10:04Z","permalink":"https://blog.coinidea.com/en/p/thinkphptable-locking-under-concurrency-in-thinkphp/","title":"[ThinkPHP]Table Locking Under Concurrency in ThinkPHP"},{"content":"This problem is a variation of binary search, but be very careful about integer overflow when summing large numbers. The correct way to compute the midpoint is left + (right - left) / 2. I used long long instead.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // Forward declaration of isBadVersion API. bool isBadVersion(int version); class Solution { public: int bSearch(long long left, long long right) { if (left \u0026gt;= right) { return right; } long long middle = (left + right) / 2; if (!isBadVersion(middle)) { if (middle + 1 \u0026gt; right) return middle; if (isBadVersion(middle + 1)) return middle + 1; else return bSearch(middle, right); } else { return bSearch(left, middle); } } int firstBadVersion(int n) { return bSearch(1, n); } }; ","date":"2017-07-18T14:17:57Z","permalink":"https://blog.coinidea.com/en/p/leetcodefirst-bad-version/","title":"[leetcode]First Bad Version"},{"content":"This problem asks to determine if a singly linked list is a palindrome. My original idea was to reverse the first half of the linked list and then traverse again, which should meet the time complexity $O(n)$ and space complexity $O(1)$ requirements, but it kept getting a time limit exceeded error for some reason.\nAfter checking the discuss section and hints, a simple recursion actually works.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public: ListNode * temp; bool isPalindrome(ListNode* head) { temp = head; return check(head); } bool check(ListNode * node) { if (node == NULL) return true; bool flag = check(node-\u0026gt;next) \u0026amp;\u0026amp; (node-\u0026gt;val == temp-\u0026gt;val); temp = temp-\u0026gt;next; return flag; } }; ","date":"2017-07-18T06:10:24Z","permalink":"https://blog.coinidea.com/en/p/leetcodepalindrome-linked-list/","title":"[leetcode]Palindrome Linked List"},{"content":"Client Class\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO.Ports; namespace COMClient { public class COMClient { private SerialPort sp = null; public COMClient(string COM) { this.sp = new SerialPort(COM); // Open a new serial port connection this.sp.Open(); // Discard data from the serial driver\u0026#39;s receive buffer this.sp.DiscardInBuffer(); // Discard data from the serial driver\u0026#39;s transmit buffer this.sp.DiscardOutBuffer(); } ~COMClient() { // Close the port connection this.sp.Close(); } public void sendMsg(string msg) { // Write the specified number of bytes to the serial port using buffer data this.sp.WriteLine(msg); } } } Client call:\n1 2 COMClient.COMClient com_client = new COMClient.COMClient(\u0026#34;COM4\u0026#34;); com_client.sendMsg(\u0026#34;Hello World!\u0026#34;); Server:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO.Ports; namespace COM_Server { class Program { static void Main(string[] args) { // Iterate through the serial port name array foreach (string port in System.IO.Ports.SerialPort.GetPortNames()) { Console.WriteLine(port); } byte[] b = new byte[32]; SerialPort sp = new SerialPort(\u0026#34;COM3\u0026#34;); while (true) { // Open a new serial port connection sp.Open(); // Discard data from the serial driver\u0026#39;s receive buffer sp.DiscardInBuffer(); // Discard data from the serial driver\u0026#39;s transmit buffer sp.DiscardOutBuffer(); // Read bytes from the serial input buffer and write them at the specified offset in a byte array string msg = sp.ReadLine(); StringBuilder sb = new StringBuilder(); Console.Write(msg); // Close the port connection sp.Close(); // Suspend the current thread for 500 milliseconds System.Threading.Thread.Sleep(500); } } } } A virtual serial port is needed here — just install VSPD. Here we configure virtual serial ports COM3 and COM4:\nServer startup screenshot:\nClient sending screenshot:\nServer receiving screenshot:\n","date":"2017-07-17T14:12:53Z","permalink":"https://blog.coinidea.com/en/p/c%23serial-port-send-and-receive-data/","title":"[C#]Serial Port Send and Receive Data"},{"content":"This problem gives an array and asks for the maximum product of a subarray, considering positive numbers, negative numbers, and zeros. The hint suggests computing a max and min for each value, then using them to generate the maximum and minimum including the current element. I used a simulation approach instead: multiply all numbers together — if the product is positive, it\u0026rsquo;s the maximum; if negative, compare the results of dropping the leftmost or rightmost negative number. To handle zeros, first split the array by zeros.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class Solution { public: int maxProductNoZero(vector\u0026lt;int\u0026gt;\u0026amp; nums) { int max = 1; int left = nums.size(); int right = -1; for (int i = 0; i \u0026lt; nums.size(); i++) { max *= nums[i]; if (nums[i] \u0026lt; 0 \u0026amp;\u0026amp; i \u0026lt; left) { left = i; } if (nums[i] \u0026lt; 0 \u0026amp;\u0026amp; i \u0026gt; right) { right = i; } } if (max \u0026lt; 0 \u0026amp;\u0026amp; nums.size() \u0026gt; 1) { int max_left = 1; for (int i = left + 1; i \u0026lt; nums.size(); i++) { max_left *= nums[i]; } int max_right = 1; for (int i = 0; i \u0026lt; right; i++) { max_right *= nums[i]; } max = max_left \u0026gt; max_right ? max_left : max_right; } return max; } int maxProduct(vector\u0026lt;int\u0026gt;\u0026amp; nums) { int max = nums[0]; vector\u0026lt;int\u0026gt; zero; zero.clear(); zero.push_back(-1); for (int i = 0; i \u0026lt; nums.size(); i++) { if (max \u0026lt; nums[i]) { max = nums[i]; } if (0 == nums[i]) { zero.push_back(i); } } zero.push_back(nums.size()); for (int i = 0; i \u0026lt; zero.size() - 1; i++) { if (zero[i + 1] - 1 \u0026gt;= zero[i] + 1) { vector\u0026lt;int\u0026gt; sub; sub.clear(); for (int j = zero[i] + 1; j \u0026lt;= zero[i + 1] - 1; j++) { sub.push_back(nums[j]); } int tmp = maxProductNoZero(sub); if (tmp \u0026gt; max) max = tmp; } } return max; } }; ","date":"2017-07-17T06:34:07Z","permalink":"https://blog.coinidea.com/en/p/leetcodemaximum-product-subarray/","title":"[leetcode]Maximum Product Subarray"},{"content":"This problem can be solved by using a hash map to store the mapping between the two strings. I initially thought it only contained lowercase letters, but it actually includes all ASCII characters. I started with one hash map, but since the mapping needs to be one-to-one, I ended up using two.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public: bool isIsomorphic(string s, string t) { if (s.length() != t.length()) return false; char hash_s[256]; char hash_t[256]; memset(hash_s, NULL, 256); memset(hash_t, NULL, 256); for (int i = 0; i \u0026lt; s.length(); i++) { if (NULL == hash_s[s[i]] \u0026amp;\u0026amp; NULL == hash_t[t[i]]) { hash_s[s[i]] = t[i]; hash_t[t[i]] = s[i]; } else { if (hash_s[s[i]] != t[i] || hash_t[t[i]] != s[i]) return false; } } return true; } }; ","date":"2017-07-14T03:38:23Z","permalink":"https://blog.coinidea.com/en/p/leetcode-isomorphic-strings/","title":"[LeetCode] Isomorphic Strings"},{"content":"For this problem I used binary search, since the array is sorted. A better approach would be to use two pointers (left and right) moving inward. I recall seeing this problem before in \u0026ldquo;The Beauty of Programming\u0026rdquo; or \u0026ldquo;Erta to Offer\u0026rdquo;.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public: vector\u0026lt;int\u0026gt; result; void bSearch(vector\u0026lt;int\u0026gt;\u0026amp; numbers, int start, int end, int find) { if (start \u0026gt; end) return; int middle = (start + end) / 2; if (find == numbers[middle]) { result.push_back(middle + 1); return; } else if (find \u0026gt; numbers[middle]) { bSearch(numbers, middle + 1, end, find); } else { bSearch(numbers, start, middle - 1, find); } } vector\u0026lt;int\u0026gt; twoSum(vector\u0026lt;int\u0026gt;\u0026amp; numbers, int target) { for (int i = 0; i \u0026lt; numbers.size(); i++) { int find = target - numbers[i]; result.push_back(i + 1); bSearch(numbers, i + 1, numbers.size(), find); if (result.size() == 2) { return result; } result.clear(); } return result; } }; ","date":"2017-07-14T03:34:59Z","permalink":"https://blog.coinidea.com/en/p/leetcodetwo-sum-ii-input-array-is-sorted/","title":"[leetcode]Two Sum II – Input array is sorted"},{"content":"This problem is simply a table join query. However, I initially thought JOIN was the same as LEFT JOIN, and used WHERE instead of ON, which resulted in an inner join. I got it wrong several times.\n1 2 3 4 select p.FirstName, p.LastName, a.City, a.State from Person as p left join Address as a on p.PersonId = a.PersonId ","date":"2017-07-14T03:31:53Z","permalink":"https://blog.coinidea.com/en/p/leetcode-combine-two-tables/","title":"[LeetCode] Combine Two Tables"},{"content":"It\u0026rsquo;s been almost two years since I last practiced problems, and the pressure is huge. I\u0026rsquo;ve been practicing recently to keep my skills sharp.\nThis problem is supposedly from \u0026ldquo;erta to Offer\u0026rdquo;. My solution obviously has issues, but it still got accepted. I\u0026rsquo;ve realized that after writing PHP, JS, and C# for so long, I\u0026rsquo;ve almost forgotten how to use Vector.\nThe correct approach for this problem should be to use one stack to maintain the minimum value — push onto it whenever a new minimum is found. Another stack holds the data. This ensures O(n) complexity with O(1) query time.\nMy somewhat naive solution:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class MinStack { private: vector\u0026lt;int\u0026gt; stack; int min; public: MinStack() { stack.clear(); } void push(int x) { if (stack.empty() || min \u0026gt; x) { min = x; } stack.push_back(x); } void pop() { if (!stack.empty()) { stack.pop_back(); genMin(); } } void genMin() { min = *(stack.begin()); for (vector\u0026lt;int\u0026gt;::iterator i = stack.begin() + 1; i \u0026lt; stack.end(); i++) { if (min \u0026gt; *i) { min = *i; } } } int top() { if (!stack.empty()) { return *(stack.end() - 1); } return false; } int getMin() { return min; } }; ","date":"2017-07-14T03:26:49Z","permalink":"https://blog.coinidea.com/en/p/leetcodemin-stack/","title":"[leetcode]Min Stack"},{"content":"A website\u0026rsquo;s articles were not displaying. My best guess was that the database was down. After connecting, the database was accessible, but the articles table could not be opened, with the error:\nTable is marked as crashed and should be repaired.\nI was startled for a moment. Although I had scheduled backups, could the database really be broken? Or was there a security vulnerability?\nBased on the literal meaning, I should repair the table.\nAfter looking it up, Navicat happens to have this feature, so I tried to repair it.\nError:\nmysql table is marked as crashed and last (automatic?) repair failed\nThe automatic repair failed.\nPrepared to check the server logs\n3.1 MySQL was running. Restarted it \u0026ndash; normal, but the articles table still couldn\u0026rsquo;t be read.\n3.2 Since the table uses the ISAM engine, I tried the method found online: myisamchk -r /your/table/data/path.MYI Still failed.\n3.3 While about to check the logs, I noticed that the disk where MySQL data was stored had run out of space \u0026ndash; 0 bytes remaining.\n3.4 Obviously, after cleaning up and moving unnecessary files, I used Navicat to repair the table, and it succeeded on the first try.\nIt\u0026rsquo;s been a long time since I wrote a blog post. I need to keep at it.\n","date":"2017-04-28T08:45:59Z","permalink":"https://blog.coinidea.com/en/p/mysql-is-marked-as-crashed-and-should-be-repaired/","title":"[MySQL] is marked as crashed and should be repaired"},{"content":" You need to use HTML5\u0026rsquo;s FileReader. Here, image-file is an input type=file file browser. If you need to restrict it to images or camera input:\n1 \u0026lt;input type=\u0026#34;file\u0026#34; accept=\u0026#34;image/*\u0026#34; capture=\u0026#34;camera\u0026#34; id=\u0026#34;image-file\u0026#34; name=\u0026#34;image-file\u0026#34; /\u0026gt; When the user selects an image, bind a change event to the input file to automatically read the local file.\n1 2 3 4 5 6 7 var image_file = document.getElementById(\u0026#34;image-file\u0026#34;); if (typeof FileReader === \u0026#39;undefined\u0026#39;) { image.innerHTML = \u0026#34;Sorry, your browser does not support FileReader\u0026#34;; image_file.setAttribute(\u0026#39;disabled\u0026#39;, \u0026#39;disabled\u0026#39;); } else { image_file.addEventListener(\u0026#39;change\u0026#39;, readFile, false); } image is an img tag with the id image. The readFile function reads the image and automatically center-crops it to a width that adapts to the screen and a fixed height of 180px. The cropping process uses Canvas.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function readFile() { var file = this.files[0]; if (!/image\\/\\w+/.test(file.type)) { alert(\u0026#34;The file must be an image!\u0026#34;); return false; } var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(e) { var image = document.getElementById(\u0026#34;image\u0026#34;); var img = new Image(); img.src = this.result; img.onload = function() { var x = 0, y = 0, width = img.width, height = img.height; if (img.width / window.innerWidth \u0026gt; img.height / 180) { width = window.innerWidth * img.height / 180; x = (img.width - width) / 2; } else { height = 180 * img.width / window.innerWidth; y = (img.height - height) / 2; } var canvas = document.createElement(\u0026#39;canvas\u0026#39;); canvas.width = window.innerWidth; canvas.height = 180; var ctx = canvas.getContext(\u0026#39;2d\u0026#39;); ctx.drawImage(img, x, y, width, height, 0, 0, canvas.width, canvas.height); var data = canvas.toDataURL(); image.innerHTML = \u0026#39;\u0026lt;img class=\u0026#34;img-responsive\u0026#34; style=\u0026#34;width:100%; height: 180px;\u0026#34; src=\u0026#34;\u0026#39; + data + \u0026#39;\u0026#34; alt=\u0026#34;\u0026#34; /\u0026gt;\u0026#39;; } } } Through these steps, the user can select an image, automatically read the local file, and then center-crop it to a width that adapts to the screen with a fixed height of 180px.\n","date":"2017-01-03T08:18:50Z","permalink":"https://blog.coinidea.com/en/p/html5-local-image-reading-and-cropping-with-html5/","title":"[HTML5] Local Image Reading and Cropping with HTML5"},{"content":" 1 update table set item=replace(replace(item, char(10), \u0026#39;\u0026#39;), char(13), \u0026#39;\u0026#39;) where condition; table: table name item: field name condition: query condition ","date":"2016-12-31T06:32:25Z","permalink":"https://blog.coinidea.com/en/p/mysql-removing-carriage-returns-and-line-feeds-from-fields/","title":"[MySQL] Removing Carriage Returns and Line Feeds from Fields"},{"content":" 1 var obj1 = JSON.parse(JSON.stringify(obj2)); The above method uses JSON round-trip conversion for deep copying arrays or objects. It has some limitations but works for most cases. For details, see\nhttps://segmentfault.com/a/1190000000501320\n","date":"2016-12-08T09:42:07Z","permalink":"https://blog.coinidea.com/en/p/javascript-deep-copy-in-javascript/","title":"[JavaScript] Deep Copy in JavaScript"},{"content":" 1 2 3 4 5 6 7 8 9 10 // Filter English punctuation $word = preg_replace(\u0026#34;/[[:punct:]]/i\u0026#34;, \u0026#34; \u0026#34;, $word); // Filter Chinese punctuation mb_regex_encoding(\u0026#39;utf-8\u0026#39;); $char = \u0026#34;。、！？：；﹑•＂…\u0026#39;\u0026#39;\u0026#34;\u0026#34;〝〞∕¦‖—　〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔！¡？¿﹖﹌﹏﹋＇´ˊˋ―﹫︳︴¯＿￣﹢﹦﹤‐­˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼（）\u0026#34;; $word = mb_ereg_replace(\u0026#34;[\u0026#34;.$char.\u0026#34;]\u0026#34;, \u0026#34; \u0026#34;, $word, \u0026#34;UTF-8\u0026#34;); // Filter consecutive spaces $word = preg_replace(\u0026#34;/\\s+/\u0026#34;, \u0026#34; \u0026#34;, $word); mb_ereg_replace is used for Chinese character replacement. When using regex, you don\u0026rsquo;t need to add / / delimiters.\n","date":"2016-12-08T09:40:15Z","permalink":"https://blog.coinidea.com/en/p/php-filtering-all-punctuation-with-php-regular-expressions/","title":"[PHP] Filtering All Punctuation with PHP Regular Expressions"},{"content":"Large-Scale Data Import and Export Note: \u0026ldquo;Large-scale\u0026rdquo; here refers to importing and exporting 100,000+ records from text files (including Office documents such as docx, xlsx).\nMySQL has two very common table types: MyISAM and InnoDB. There are many comparisons of these two types online. The main difference is that InnoDB supports transactions and row-level locking, while MyISAM does not. MyISAM is relatively more efficient, and each has its own advantages and disadvantages.\nUse Cases for MyISAM and InnoDB\nMyISAM is suitable for:\nFrequent COUNT calculations; Infrequent inserts but frequent queries; No transactions needed. InnoDB is suitable for:\nHigh reliability requirements or transaction support needed; Frequent table updates and queries with high likelihood of table locking. Differences Between MyISAM and InnoDB MyISAM does not support advanced features like transactions, while InnoDB does. MyISAM tables do not support foreign keys. During write operations (insert, update, delete), MyISAM locks the entire table, while InnoDB locks only the affected rows. When your database has heavy writes, updates, and deletions with relatively few queries, or when data integrity requirements are high, choose InnoDB. When your database is primarily read-heavy with relatively few updates and writes, and data integrity requirements are less strict, choose MyISAM, as its query performance is faster than InnoDB. In summary, InnoDB is a good choice for this scenario.\nOptimization Methods for Inserting Large Amounts of Data When PHP needs to insert large amounts of data, inserting one record at a time results in severe I/O performance bottlenecks.\nDemo Code: 1 2 3 4 5 6 7 $params = array(\u0026#39;value\u0026#39; =\u0026gt; \u0026#39;50\u0026#39;); set_time_limit(0); echo date(\u0026#34;H:i:s\u0026#34;); for($i = 0; $i \u0026lt; 2000000; $i++) { $connect_mysql-\u0026gt;insert($params); } echo date(\u0026#34;H:i:s\u0026#34;); There are two methods to solve this problem:\n1. Using Transactions (InnoDB supported) For example, you can commit a transaction every 10,000 or 100,000 records, which greatly reduces I/O.\n1 2 3 4 5 6 7 8 9 10 11 12 echo date(\u0026#34;H:i:s\u0026#34;); $connect_mysql-\u0026gt;query(\u0026#39;BEGIN\u0026#39;); $params = array(\u0026#39;value\u0026#39; =\u0026gt; \u0026#39;50\u0026#39;); for($i = 0; $i \u0026lt; 2000000; $i++) { $connect_mysql-\u0026gt;insert($params); if($i % 100000 == 0) { $connect_mysql-\u0026gt;query(\u0026#39;COMMIT\u0026#39;); $connect_mysql-\u0026gt;query(\u0026#39;BEGIN\u0026#39;); } } $connect_mysql-\u0026gt;query(\u0026#39;COMMIT\u0026#39;); echo date(\u0026#34;H:i:s\u0026#34;); 2. SQL Statement Concatenation This is a MySQL feature that uses optimized SQL statements: concatenate SQL statements using insert into table () values (),(),(),() and insert them all at once. If the string is too long, you need to configure MySQL by running:\n1 SET GLOBAL max_allowed_packet = 2 * 1024 * 1024 * 10; 1 2 3 4 5 6 $sql = \u0026#34;INSERT INTO twenty_million (value) VALUES\u0026#34;; for($i = 0; $i \u0026lt; 2000000; $i++) { $sql .= \u0026#34;(\u0026#39;50\u0026#39;),\u0026#34;; } $sql = substr($sql, 0, strlen($sql) - 1); $connect_mysql-\u0026gt;query($sql); The first method is more commonly used, while the second is mostly for test data.\nBy default, PHP has a memory limit of 128MB. When ThinkPHP exceeds this memory limit, you can either increase PHP\u0026rsquo;s default maximum memory or simply remove the APP_DEBUG constant definition in the entry file or set it to false. This will save a lot of memory. Of course, you can also use transaction mode to commit every n records. ThinkPHP\u0026rsquo;s addAll function can also be used for batch inserts, though it has quite a few bugs.\nStarting and Committing Transactions in ThinkPHP 1 2 $table-\u0026gt;startTrans(); $table-\u0026gt;commit(); When working with Office files, PHPWord and PHPExcel are recommended.\n","date":"2016-12-08T09:37:45Z","permalink":"https://blog.coinidea.com/en/p/php-large-scale-data-import-and-export-with-thinkphp-php-and-mysql/","title":"[PHP] Large-Scale Data Import and Export with ThinkPHP, PHP, and MySQL"},{"content":"I recently needed to migrate from DedeCMS (dedecms) to Discuz Portal. The most important challenge was how to migrate categories and a large number of articles. The database tables involved are:\ndede_addonarticle - Article table dede_arctype - Category table dede_relation - Old-to-new category mapping table pre_portal_article_content - Article content table pre_portal_article_title - Article title table pre_portal_article_count - Article view count table 1. Preprocess the old table, merge typename 1 2 3 UPDATE dede_addonarticle, dede_arctype SET dede_addonarticle.typename = dede_arctype.typename WHERE dede_arctype.id = dede_addonarticle.typeid; 2. Merge click, title, writer, pubdate, keywords, description 1 2 3 4 5 6 7 8 9 UPDATE dede_addonarticle, dede_archives SET dede_addonarticle.click = dede_archives.click, dede_addonarticle.title = dede_archives.title, dede_addonarticle.writer = dede_archives.writer, dede_addonarticle.pubdate = dede_archives.pubdate, dede_addonarticle.keywords = dede_archives.keywords, dede_addonarticle.description = dede_archives.description WHERE dede_archives.id = dede_addonarticle.aid; 3. Generate new IDs in relation 1 2 3 UPDATE dede_relation, pre_portal_category SET dede_relation.catid = pre_portal_category.catid WHERE dede_relation.new = pre_portal_category.catname; 4. Populate catid based on typename and relation 1 2 3 UPDATE dede_addonarticle, dede_relation SET dede_addonarticle.catid = dede_relation.catid WHERE dede_addonarticle.typename LIKE CONCAT(\u0026#34;%\u0026#34;, dede_relation.olds, \u0026#34;%\u0026#34;); 5. Import into Discuz Portal Tables Insert into pre_portal_article_content (Article content table) 1 2 3 INSERT INTO pre_portal_article_content(aid, title, content, dateline) SELECT aid, title, body, pubdate AS dateline FROM dede_addonarticle; Insert into pre_portal_article_title (Article title table) 1 2 3 INSERT INTO pre_portal_article_title(aid, username, title, author, summary, dateline) SELECT aid, \u0026#39;admin\u0026#39;, title, writer AS author, description AS summary, pubdate AS dateline FROM dede_addonarticle; Insert into pre_portal_article_count (Article view count table) 1 2 3 INSERT INTO pre_portal_article_count(aid, cid, viewnum) SELECT aid, catid, click FROM dede_addonarticle; ","date":"2016-11-18T05:14:05Z","permalink":"https://blog.coinidea.com/en/p/web-development-migrating-dedecms-to-discuz-portal/","title":"[Web Development] Migrating DedeCMS to Discuz Portal"},{"content":"Recommending a Web Development Debugging Tool It is especially useful for reading, modifying, and adding Cookie, Session, Header, GET, and POST data during network transmission. There are many blog posts about it online, so I won\u0026rsquo;t go into detail here.\nPostman has three versions (as of November 2016):\nPostman for Chrome Postman for Mac Postman for Linux (Beta) The Chrome plugin is recommended. However, it\u0026rsquo;s not easy to download in China. Here is the official Google Chrome plugin download link as of November 2016:\nhttps://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop/related\nAnd a very old version download: Postman-REST-Client_v0.8.4.14\nLink: http://pan.baidu.com/s/1bo4nzQJ Password: h0w7\n","date":"2016-11-18T04:59:52Z","permalink":"https://blog.coinidea.com/en/p/web-development-postman-plugin/","title":"[Web Development] Postman Plugin"},{"content":"Solution on Windows In php.ini, enable the mbstring library: remove the semicolon before extension=php_mbstring.dll.\nSolution on Linux First, install the php-mbstring library:\n1 yum install php-mbstring Then, edit the /etc/php.ini file and add the following line:\n1 extension=mbstring.so Save and restart the httpd service:\n1 service httpd restart ","date":"2016-08-02T03:37:01Z","permalink":"https://blog.coinidea.com/en/p/php-call-to-undefined-function-mb_convert_encoding/","title":"[PHP] call to undefined function mb_convert_encoding"},{"content":"While deploying an IIS service recently, I noticed that some .ttf, .otf, .woff and other font files were not being loaded, even though js, css, images and other files loaded successfully. The reason is that IIS cannot serve files that don\u0026rsquo;t have a default MIME mapping.\nThe solution is simple \u0026ndash; add the corresponding MIME type mappings. You can add them directly in the IIS panel under MIME Types. For specific type information, refer to the W3CSchool MIME Reference: http://www.w3school.com.cn/media/media_mimeref.asp\nMIME mappings for font files:\n1 2 3 4 5 6 \u0026lt;mimeMap fileExtension=\u0026#34;.woff\u0026#34; mimeType=\u0026#34;application/x-font-woff\u0026#34; /\u0026gt; \u0026lt;mimeMap fileExtension=\u0026#34;.woff2\u0026#34; mimeType=\u0026#34;application/x-font-woff2\u0026#34; /\u0026gt; \u0026lt;mimeMap fileExtension=\u0026#34;.ttf\u0026#34; mimeType=\u0026#34;application/x-font-truetype\u0026#34; /\u0026gt; \u0026lt;mimeMap fileExtension=\u0026#34;.svg\u0026#34; mimeType=\u0026#34;image/svg+xml\u0026#34; /\u0026gt; \u0026lt;mimeMap fileExtension=\u0026#34;.otf\u0026#34; mimeType=\u0026#34;application/x-font-opentype\u0026#34; /\u0026gt; \u0026lt;mimeMap fileExtension=\u0026#34;.eot\u0026#34; mimeType=\u0026#34;application/vnd.ms-fontobject\u0026#34; /\u0026gt; ","date":"2016-07-28T09:07:08Z","permalink":"https://blog.coinidea.com/en/p/iis-file-formats-fonts-failing-to-load-on-iis-server/","title":"[IIS] File Formats (Fonts) Failing to Load on IIS Server"},{"content":"In web and mobile frontend development, developers often want to use non-system fonts, which are typically in TTF, OTF, and other formats.\nEnglish fonts are usually quite small, but Chinese fonts can range from 1-2 MB on the small end to over 10 MB for larger ones. This is unacceptable for web or mobile applications. This is where font subsetting comes in \u0026ndash; you only need the specific characters used in a particular frontend interface, so you export just those characters from the font into a new TTF file, leaving out the unnecessary ones.\nI highly recommend a Chinese font subsetting tool: TTF Font Library Subsetting and Conversion Tool\nDownload link: http://pan.baidu.com/s/1skI7FiP Password: qb27\nNote that the target font to be subsetted must first be installed in the Windows system.\n","date":"2016-07-22T02:35:14Z","permalink":"https://blog.coinidea.com/en/p/font-subsetting-for-web-and-mobile/","title":"Font Subsetting for Web and Mobile"},{"content":"Written at Graduation One year ago, I officially graduated and entered the workforce. \u0026ndash; Written at Graduation\nI\u0026rsquo;m grateful for the words my past self left me: \u0026ldquo;As long as your spirit never dies, life keeps running on the road.\u0026rdquo;\nIf I were to leave a message for next year\u0026rsquo;s me, it would be: \u0026ldquo;Persist, be strong, be resilient.\u0026rdquo;\nThis year, I got some of the things I wanted, but I also paid a heavy price. While chasing those things, I suddenly realized that the health of my family is what matters most.\nIndeed, when the sunlight shines down, what could be happier than simply being alive?\n\u0026ndash; DevHu, recorded on July 2, 2016, still in a rented apartment\nJanuary 4, 2018 update: Due to reasons I\u0026rsquo;d rather not explain, I\u0026rsquo;ll use this post as my 2016 year-end review.\n","date":"2016-07-01T16:32:42Z","permalink":"https://blog.coinidea.com/en/p/year-end-review-my-2016--one-year-after-graduation/","title":"[Year-End Review] My 2016 -- One Year After Graduation"},{"content":"Using the bootstrap-hover-dropdown Plugin 1. Download bootstrap-hover-dropdown Download link: http://www.bootcdn.cn/bootstrap-hover-dropdown/\nOf course, you can also use the CDN version directly.\n2. Include bootstrap-hover-dropdown.js In your HTML file, make sure to include bootstrap-hover-dropdown.js. Typically, you can place it in a \u0026lt;script\u0026gt; tag at the bottom of the page:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Bootstrap Hover Dropdown Example\u0026lt;/title\u0026gt; \u0026lt;!-- Include Bootstrap CSS --\u0026gt; \u0026lt;link href=\u0026#34;https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css\u0026#34; rel=\u0026#34;stylesheet\u0026#34;\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;!-- Your content --\u0026gt; \u0026lt;!-- Include jQuery --\u0026gt; \u0026lt;script src=\u0026#34;https://code.jquery.com/jquery-3.5.1.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;!-- Include Bootstrap JS --\u0026gt; \u0026lt;script src=\u0026#34;https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;!-- Include bootstrap-hover-dropdown.js --\u0026gt; \u0026lt;script src=\u0026#34;path/to/bootstrap-hover-dropdown.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 3. Modify the Dropdown in HTML Find the element with the dropdown-toggle class in your HTML file and modify it as follows:\n1 \u0026lt;a href=\u0026#34;#\u0026#34; class=\u0026#34;dropdown-toggle\u0026#34; data-toggle=\u0026#34;dropdown\u0026#34;\u0026gt;Dropdown\u0026lt;/a\u0026gt; Change it to:\n1 \u0026lt;a href=\u0026#34;#\u0026#34; class=\u0026#34;dropdown-toggle\u0026#34; data-hover=\u0026#34;dropdown\u0026#34; data-close-others=\u0026#34;true\u0026#34;\u0026gt;Dropdown\u0026lt;/a\u0026gt; You can also add a parameter data-delay=\u0026quot;1000\u0026quot;, which sets the delay before the dropdown disappears (default is 500 milliseconds). For example:\n1 \u0026lt;a href=\u0026#34;#\u0026#34; class=\u0026#34;dropdown-toggle\u0026#34; data-hover=\u0026#34;dropdown\u0026#34; data-close-others=\u0026#34;true\u0026#34; data-delay=\u0026#34;1000\u0026#34;\u0026gt;Dropdown\u0026lt;/a\u0026gt; 4. Removing the Delay If you want to completely remove the delay, you can directly modify the configuration in the bootstrap-hover-dropdown.js file, changing delay: 500 to delay: 0.\nFind and modify the following code:\n1 delay: 500 Change it to:\n1 delay: 0 This will remove the dropdown menu delay.\n","date":"2016-05-27T03:18:37Z","permalink":"https://blog.coinidea.com/en/p/bootstrap-triggering-dropdown-toggle-on-mouse-hover-in-bootstrap/","title":"[Bootstrap] Triggering dropdown-toggle on Mouse Hover in Bootstrap"},{"content":"1. UEditor + Node.js Image Upload UEditor is a feature-rich open-source rich text editor by Baidu.\nDownload link: http://ueditor.baidu.com/website/download.html\nIt currently provides versions for PHP, ASP, .Net, and JSP. UEditor is primarily built with frontend HTML, CSS, and JS. The reason it is further divided by server-side language is, in my understanding, mainly for the image upload functionality which involves server interaction.\nAmong the many versions, there is no Node.js version. Below I will explain how to convert the PHP version of UEditor into a Node.js version.\nAfter examining all requests in the PHP version, I found that the action parameter values include config (configuration file), uploadimage (image upload), listimage (online management), and catchimage (image capture). So we just need to rewrite these 4 request handlers to meet our needs.\n1.1 Modify the serverUrl property in UEditor\u0026rsquo;s ueditor.config.js: 1 serverUrl: \u0026#39;/ue/uploads\u0026#39; 1.2 Rename ueditor/php/config.json to config.js and move it to the ueditor directory. 1.3 Next, write the four corresponding actions on the Node.js side. The image upload uses the connect-busboy middleware. Code as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 // Image upload var path = require(\u0026#39;path\u0026#39;); var uploadsPath = path.resolve(\u0026#39;public/uploads\u0026#39;) + \u0026#39;/\u0026#39;; // Path to store images var busboy = require(\u0026#39;connect-busboy\u0026#39;); app.use(busboy({ limits: { fileSize: 10 * 1024 * 1024 // 10MB } })); var action = { // Upload image uploadimage: function (req, res) { var fstream; req.pipe(req.busboy); req.busboy.on(\u0026#39;file\u0026#39;, function (fieldname, file, filename, encoding, mimetype) { var filesize = 0; var ext = path.extname(filename); var newFilename = (new Date() - 0) + ext; fstream = fs.createWriteStream(uploadsPath + newFilename); file.on(\u0026#39;data\u0026#39;, function (data) { filesize = data.length; }); fstream.on(\u0026#39;close\u0026#39;, function () { console.log(JSON.stringify({ \u0026#34;originalName\u0026#34;: filename, \u0026#34;name\u0026#34;: newFilename, \u0026#34;url\u0026#34;: \u0026#39;/uploads/\u0026#39; + newFilename, \u0026#34;type\u0026#34;: ext, \u0026#34;size\u0026#34;: filesize, \u0026#34;state\u0026#34;: \u0026#34;SUCCESS\u0026#34; })); res.send(JSON.stringify({ \u0026#34;originalName\u0026#34;: filename, \u0026#34;name\u0026#34;: newFilename, \u0026#34;url\u0026#34;: \u0026#39;/uploads/\u0026#39; + newFilename, \u0026#34;type\u0026#34;: ext, \u0026#34;size\u0026#34;: filesize, \u0026#34;state\u0026#34;: \u0026#34;SUCCESS\u0026#34; })); }); file.pipe(fstream); }); }, // Get configuration file config: function (req, res) { return res.redirect(\u0026#39;/js/UEditor/config.js\u0026#39;); }, // Online management listimage: function (req, res) { fs.readdir(uploadsPath, function (err, files) { var total = 0, list = []; files.sort().splice(req.query.start, req.query.size).forEach(function (a, b) { /^.+\\..+$/.test(a) \u0026amp;\u0026amp; list.push({ url: \u0026#39;/uploads/\u0026#39; + a, mtime: new Date(fs.statSync(uploadsPath + a).mtime).getTime() }); }); total = list.length; res.json({state: total === 0 ? \u0026#39;no match file\u0026#39; : \u0026#39;SUCCESS\u0026#39;, list: list, total: total, start: req.query.start}); }); }, // Catch image (save image to server when pasting) catchimage: function (req, res) { var list = []; req.body.source.forEach(function (src, index) { http.get(src, function (_res) { var imagedata = \u0026#39;\u0026#39;; _res.setEncoding(\u0026#39;binary\u0026#39;); _res.on(\u0026#39;data\u0026#39;, function (chunk) { imagedata += chunk }); _res.on(\u0026#39;end\u0026#39;, function () { var pathname = url.parse(src).pathname; var original = pathname.match(/[^/]+\\.\\w+$/g)[0]; var suffix = original.match(/[^\\.]+$/)[0]; var filename = Date.now() + \u0026#39;.\u0026#39; + suffix; var filepath = uploadsPath + \u0026#39;catchimages/\u0026#39; + filename; fs.writeFile(filepath, imagedata, \u0026#39;binary\u0026#39;, function (err) { list.push({ original: original, source: src, state: err ? \u0026#34;ERROR\u0026#34; : \u0026#34;SUCCESS\u0026#34;, title: filename, url: \u0026#39;/uploads/catchimages/\u0026#39; + filename }); }) }); }) }); var f = setInterval(function () { if (req.body.source.length === list.length) { clearInterval(f); res.json({state: \u0026#34;SUCCESS\u0026#34;, list: list}); } }, 50); } }; app.get(\u0026#39;/ue/uploads\u0026#39;, function (req, res) { action[req.query.action](req, res); }); app.post(\u0026#39;/ue/uploads\u0026#39;, function (req, res) { action[req.query.action](req, res); }); The above mainly references this blog: http://www.xiaoboy.com/detail/1341545081.html\n2. GoLang Installation and Configuration In section 1, UEditor uploads images to the /public/uploads/ folder on the Node.js server. If you need an image server with high storage, portability, and scalability, you need to set up a dedicated server. This article uses the open-source distributed image (file) server seaweedfs.\nGitHub link: https://github.com/chrislusf/seaweedfs\nThis server is written in GoLang, so you need to install and configure GoLang. Download link for China: http://www.golangtc.com/download \u0026ndash; choose the appropriate package for your operating system. This article demonstrates installation on Windows 7 x64. After a straightforward installation, you need to configure the following environment variables:\n1 2 3 GOROOT=D:\\Go16 GOPATH=D:\\ImageServer\\seaweedfs PATH=D:\\Go16\\bin The GOPATH environment variable is very important \u0026ndash; your own code must be placed in the directory configured by this variable for the Go compiler to find and compile it.\n3. Compiling and Running seaweedfs Clone the seaweedfs code from GitHub, then follow the makefile instructions or run the makefile directly. In the seaweedfs directory, run the following commands in the console:\n1 2 3 4 5 6 go clean -i -v ./go/weed/ rm -f weed #for linux go get -v -d ./go/weed go build -v -o weed ./go/weed Some dependencies may fail to download during go get and need to be downloaded manually and placed in the \\seaweedfs\\src directory.\nHere is a recommended Go package download site: https://gopm.io/download?pkgname=golang.org/x/net\nAfter building, a weed binary will be generated in the seaweedfs directory. You can also rename it to weed.exe. Now you can start weed. Using the local machine as an example:\n1 weed master 1 weed volume --dir=\u0026#34;./tmp/data1\u0026#34; --max=5 --mserver=\u0026#34;localhost:9333\u0026#34; --port=8080 \u0026amp; Following the GitHub instructions, uploading and downloading images works without issues. At this point, the basic image server setup is complete.\nModify the Node.js image upload code as follows:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 // Image upload var path = require(\u0026#39;path\u0026#39;); var multipart = require(\u0026#39;connect-multiparty\u0026#39;); var multipartMiddleware = multipart(); function curlPostAssign(res, filepath, filename, filesize) { request.post(config.url_image + \u0026#39;dir/assign\u0026#39;,{}, function (error, response, body) { if (!error \u0026amp;\u0026amp; response.statusCode == 200) { assign = eval(\u0026#39;(\u0026#39; + body + \u0026#39;)\u0026#39;); var result = {}; result.res = res; result.json = JSON.stringify({ \u0026#34;originalName\u0026#34;: filename, \u0026#34;name\u0026#34;: assign.fid, \u0026#34;url\u0026#34;: \u0026#39;/res?fid=\u0026#39; + assign.fid, \u0026#34;type\u0026#34;: ext, \u0026#34;size\u0026#34;: filesize, \u0026#34;state\u0026#34;: \u0026#34;SUCCESS\u0026#34; }); curlPostWrite(assign.fid, filepath, assign.publicUrl, result); var ext = path.extname(filename); } else { console.log(\u0026#34;Image server assign error...\u0026#34;) } }); } function curlPostWrite(fid, tmp_file, publicUrl, result) { var files = [ {urlKey: \u0026#34;file1\u0026#34;, urlValue: tmp_file} ] var options = { host: publicUrl.split(\u0026#34;:\u0026#34;)[0], port: publicUrl.split(\u0026#34;:\u0026#34;)[1], method: \u0026#34;POST\u0026#34;, path: \u0026#34;/\u0026#34; + fid } var req = http.request(options, function(res){ res.on(\u0026#34;data\u0026#34;, function(chunk){ }) }) req.on(\u0026#39;error\u0026#39;, function(e){ console.log(\u0026#39;problem with request:\u0026#39; + e.message); console.log(e); }) postfile.postFile(files, req, result); } var action = { // Upload image uploadimage: function(req, res) { curlPostAssign(res, req.files.upfile.path, req.files.upfile.originalFilename, req.files.upfile.size); }, // Get configuration file config: function (req, res) { return res.redirect(\u0026#39;/js/UEditor/config.js\u0026#39;); }, // Online management listimage: function (req, res) { fs.readdir(uploadsPath, function (err, files) { var total = 0, list = []; files.sort().splice(req.query.start, req.query.size).forEach(function (a, b) { /^.+\\..+$/.test(a) \u0026amp;\u0026amp; list.push({ url: \u0026#39;/uploads/\u0026#39; + a, mtime: new Date(fs.statSync(uploadsPath + a).mtime).getTime() }); }); total = list.length; res.json({state: total === 0 ? \u0026#39;no match file\u0026#39; : \u0026#39;SUCCESS\u0026#39;, list: list, total: total, start: req.query.start}); }); }, // Catch image (save image to server when pasting) catchimage: function (req, res) { var list = []; req.body.source.forEach(function (src, index) { http.get(src, function (_res) { var imagedata = \u0026#39;\u0026#39;; _res.setEncoding(\u0026#39;binary\u0026#39;); _res.on(\u0026#39;data\u0026#39;, function (chunk) { imagedata += chunk }); _res.on(\u0026#39;end\u0026#39;, function () { var pathname = url.parse(src).pathname; var original = pathname.match(/[^/]+\\.\\w+$/g)[0]; var suffix = original.match(/[^\\.]+$/)[0]; var filename = Date.now() + \u0026#39;.\u0026#39; + suffix; var filepath = uploadsPath + \u0026#39;catchimages/\u0026#39; + filename; fs.writeFile(filepath, imagedata, \u0026#39;binary\u0026#39;, function (err) { list.push({ original: original, source: src, state: err ? \u0026#34;ERROR\u0026#34; : \u0026#34;SUCCESS\u0026#34;, title: filename, url: \u0026#39;/uploads/catchimages/\u0026#39; + filename }); }) }); }) }); var f = setInterval(function () { if (req.body.source.length === list.length) { clearInterval(f); res.json({state: \u0026#34;SUCCESS\u0026#34;, list: list}); } }, 50); } }; app.get(\u0026#39;/ue/uploads\u0026#39;, multipartMiddleware, function (req, res) { action[req.query.action](req, res); }); app.post(\u0026#39;/ue/uploads\u0026#39;, multipartMiddleware, function (req, res) { action[req.query.action](req, res); }); Running result:\n","date":"2016-05-18T03:16:01Z","permalink":"https://blog.coinidea.com/en/p/node.js-building-an-image-server-with-ueditor--node.js--seaweedfs/","title":"[Node.js] Building an Image Server with UEditor + Node.js + SeaweedFS"},{"content":"Scheduled backup is an extremely important task in database services.\nFor most users who manage databases with a GUI (commonly MySQL-Front, Navicat, or MySQL Workbench), interactive backup methods are simple and easy to learn.\nHere is a brief guide on how to set up scheduled backups using MySQL-Front (version 5.3):\nAfter connecting to the database, go to \u0026ldquo;Extras\u0026rdquo; -\u0026gt; \u0026ldquo;Jobs\u0026rdquo; -\u0026gt; \u0026ldquo;New\u0026rdquo; -\u0026gt; \u0026ldquo;Export\u0026rdquo; Select the test database and click Next. Specify the export path \u0026ldquo;D:\\test.sql\u0026rdquo;. Note that the character set should generally be set to UTF-8. Next, specify the export content \u0026ndash; make sure to check the data option. Set the backup time and interval. After completion, a job named \u0026ldquo;test\u0026rdquo; will appear in the scheduled tasks section. If you want to run it immediately, right-click and select Run. ","date":"2016-05-05T03:08:32Z","permalink":"https://blog.coinidea.com/en/p/mysql-scheduled-backup-with-mysql-front-on-windows/","title":"[MySQL] Scheduled Backup with MySQL-Front on Windows"},{"content":"As described in the previous blog post about creating a Maven project, create a Spring Maven project.\nPOM File Configuration: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 \u0026lt;project xmlns=\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://maven.apache.org/POM/4.0.0 http://www.w3.org/2001/XMLSchema-instance\u0026#34;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;groupId\u0026gt;com.coinidea\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;web\u0026lt;/artifactId\u0026gt; \u0026lt;packaging\u0026gt;war\u0026lt;/packaging\u0026gt; \u0026lt;version\u0026gt;1.0-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;hive.web Maven Webapp\u0026lt;/name\u0026gt; \u0026lt;url\u0026gt;http://maven.apache.org\u0026lt;/url\u0026gt; \u0026lt;properties\u0026gt; \u0026lt;spring.version\u0026gt;4.2.5.RELEASE\u0026lt;/spring.version\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;junit\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;junit\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.8.1\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--spring--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-context\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-core\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-web\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-webmvc\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-test\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; \u0026lt;build\u0026gt; \u0026lt;finalName\u0026gt;web\u0026lt;/finalName\u0026gt; \u0026lt;/build\u0026gt; \u0026lt;repositories\u0026gt; \u0026lt;repository\u0026gt; \u0026lt;id\u0026gt;people.apache.snapshots\u0026lt;/id\u0026gt; \u0026lt;url\u0026gt;http://repository.apache.org/content/groups/snapshots-group/\u0026lt;/url\u0026gt; \u0026lt;releases\u0026gt; \u0026lt;enabled\u0026gt;false\u0026lt;/enabled\u0026gt; \u0026lt;/releases\u0026gt; \u0026lt;snapshots\u0026gt; \u0026lt;enabled\u0026gt;true\u0026lt;/enabled\u0026gt; \u0026lt;/snapshots\u0026gt; \u0026lt;/repository\u0026gt; \u0026lt;/repositories\u0026gt; \u0026lt;/project\u0026gt; Install Tomcat locally. If you don\u0026rsquo;t know how to install Tomcat, please search for instructions online.\nTomcat Configuration Run -\u0026gt; Edit Configurations, click \u0026ldquo;+\u0026rdquo;, and select Tomcat Local.\nIn the \u0026ldquo;Server\u0026rdquo; tab, configure the local Tomcat path; in \u0026ldquo;Deployment\u0026rdquo;, select \u0026ldquo;+\u0026rdquo; -\u0026gt; Artifact. After running, the default Hello World page will pop up. Create your own Controller web.xml configuration 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;web-app xmlns=\u0026#34;http://xmlns.jcp.org/xml/ns/javaee\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\u0026#34; version=\u0026#34;3.1\u0026#34;\u0026gt; \u0026lt;context-param\u0026gt; \u0026lt;param-name\u0026gt;contextConfigLocation\u0026lt;/param-name\u0026gt; \u0026lt;param-value\u0026gt;/WEB-INF/applicationContext.xml\u0026lt;/param-value\u0026gt; \u0026lt;/context-param\u0026gt; \u0026lt;listener\u0026gt; \u0026lt;listener-class\u0026gt;org.springframework.web.context.ContextLoaderListener\u0026lt;/listener-class\u0026gt; \u0026lt;/listener\u0026gt; \u0026lt;servlet\u0026gt; \u0026lt;servlet-name\u0026gt;dispatcher\u0026lt;/servlet-name\u0026gt; \u0026lt;servlet-class\u0026gt;org.springframework.web.servlet.DispatcherServlet\u0026lt;/servlet-class\u0026gt; \u0026lt;load-on-startup\u0026gt;1\u0026lt;/load-on-startup\u0026gt; \u0026lt;/servlet\u0026gt; \u0026lt;servlet-mapping\u0026gt; \u0026lt;servlet-name\u0026gt;dispatcher\u0026lt;/servlet-name\u0026gt; \u0026lt;url-pattern\u0026gt;/\u0026lt;/url-pattern\u0026gt; \u0026lt;/servlet-mapping\u0026gt; \u0026lt;servlet-mapping\u0026gt; \u0026lt;servlet-name\u0026gt;default\u0026lt;/servlet-name\u0026gt; \u0026lt;url-pattern\u0026gt;*.css\u0026lt;/url-pattern\u0026gt; \u0026lt;/servlet-mapping\u0026gt; \u0026lt;servlet-mapping\u0026gt; \u0026lt;servlet-name\u0026gt;default\u0026lt;/servlet-name\u0026gt; \u0026lt;url-pattern\u0026gt;*.gif\u0026lt;/url-pattern\u0026gt; \u0026lt;/servlet-mapping\u0026gt; \u0026lt;servlet-mapping\u0026gt; \u0026lt;servlet-name\u0026gt;default\u0026lt;/servlet-name\u0026gt; \u0026lt;url-pattern\u0026gt;*.jpg\u0026lt;/url-pattern\u0026gt; \u0026lt;/servlet-mapping\u0026gt; \u0026lt;servlet-mapping\u0026gt; \u0026lt;servlet-name\u0026gt;default\u0026lt;/servlet-name\u0026gt; \u0026lt;url-pattern\u0026gt;*.js\u0026lt;/url-pattern\u0026gt; \u0026lt;/servlet-mapping\u0026gt; \u0026lt;/web-app\u0026gt; It is worth noting that the default servlet-mapping configuration above solves the Spring static file 404 issue.\nAll other URLs will go through the dispatcher configuration for URL mapping.\n7. dispatcher-servlet.xml configuration\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 \u0026lt;beans xmlns=\u0026#34;http://www.springframework.org/schema/beans\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xmlns:context=\u0026#34;http://www.springframework.org/schema/context\u0026#34; xmlns:task=\u0026#34;http://www.springframework.org/schema/task\u0026#34; xsi:schemaLocation=\u0026#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd\u0026#34; default-lazy-init=\u0026#34;false\u0026#34;\u0026gt; \u0026lt;bean class=\u0026#34;org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping\u0026#34;/\u0026gt; \u0026lt;bean class=\u0026#34;org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter\u0026#34;/\u0026gt; \u0026lt;!-- Enable Spring MVC annotations --\u0026gt; \u0026lt;context:annotation-config /\u0026gt; \u0026lt;!-- Set the package where annotated classes are located --\u0026gt; \u0026lt;context:component-scan base-package=\u0026#34;com.coinidea.controller\u0026#34;/\u0026gt; \u0026lt;!-- View resolver for page paths. prefix: prefix, suffix: suffix --\u0026gt; \u0026lt;bean class=\u0026#34;org.springframework.web.servlet.view.InternalResourceViewResolver\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;prefix\u0026#34; value=\u0026#34;/WEB-INF/views/\u0026#34;/\u0026gt; \u0026lt;property name=\u0026#34;suffix\u0026#34; value=\u0026#34;.jsp\u0026#34;/\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;/beans\u0026gt; This specifies that the JSP view folder is located at /WEB-INF/views/ and enables Spring\u0026rsquo;s annotation features. All Controllers will be looked up in the package com.coinidea.controller.\n8. FirstHello Controller\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.cmri.web.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping(\u0026#34;/first\u0026#34;) public class TestController { @RequestMapping(\u0026#34;hello\u0026#34;) public ModelAndView view() { ModelAndView mv = new ModelAndView(); mv.addObject(\u0026#34;message\u0026#34;, \u0026#34;HelloWorld!\u0026#34;); mv.setViewName(\u0026#34;hello\u0026#34;); return mv; } } hello.jsp in the views folder:\n1 2 3 4 5 6 7 8 9 \u0026lt;%@ page language=\u0026#34;java\u0026#34; contentType=\u0026#34;text/html; charset=UTF-8\u0026#34; pageEncoding=\u0026#34;UTF-8\u0026#34;%\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;hello world\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; ${message} \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; When you visit http://localhost:8080/first/hello in the browser, it will display:\n9. Java Web API Controller\nWhen you need to respond to Ajax requests, add the following annotation to the method:\n1 2 3 4 5 @RequestMapping(\u0026#34;ajax\u0026#34;) @ResponseBody public String ajax() { return \u0026#34;Hello world\u0026#34;; } ","date":"2016-04-28T07:24:58Z","permalink":"https://blog.coinidea.com/en/p/spring-creating-a-spring-framework-project-and-adding-your-own-controller-in-intellij-idea/","title":"[Spring] Creating a Spring Framework Project and Adding Your Own Controller in IntelliJ IDEA"},{"content":"Hadoop has many versions, and if the version is wrong, connecting to and operating Hive may throw all sorts of errors. This is where Maven, mentioned in the previous blog post, comes in handy for managing these libraries.\nChecking Hadoop and Hive versions:\n1 2 hadoop version hive --version POM configuration:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 \u0026lt;project xmlns=\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\u0026#34;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;groupId\u0026gt;com.coinidea\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;hive\u0026lt;/artifactId\u0026gt; \u0026lt;packaging\u0026gt;war\u0026lt;/packaging\u0026gt; \u0026lt;version\u0026gt;1.0-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;hive.web Maven Webapp\u0026lt;/name\u0026gt; \u0026lt;url\u0026gt;http://maven.apache.org\u0026lt;/url\u0026gt; \u0026lt;properties\u0026gt; \u0026lt;hadoop.version\u0026gt;2.5.0-cdh5.3.2\u0026lt;/hadoop.version\u0026gt; \u0026lt;hive.version\u0026gt;0.13.1-cdh5.3.2\u0026lt;/hive.version\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;dependencies\u0026gt; \u0026lt;!--hadoop and hive--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.hive\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;hive-jdbc\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${hive.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.hive\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;hive-common\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${hive.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.hive\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;hive-exec\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${hive.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.hive\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;hive-metastore\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${hive.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.hive\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;hive-service\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${hive.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.apache.hadoop\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;hadoop-common\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${hadoop.version}\u0026lt;/version\u0026gt; \u0026lt;exclusions\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;org.mortbay.jetty\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jetty\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;org.mortbay.jetty\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jetty-util\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;org.mortbay.jetty\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jsp-2.1\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;org.mortbay.jetty\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jsp-api-2.1\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;org.mortbay.jetty\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;servlet-api-2.1\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;javax.servlet\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;servlet-api\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;javax.servlet.jsp\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jsp-api\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;!--tomcat7 includes jasper.jar--\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;tomcat\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jasper-compiler\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;tomcat\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;jasper-runtime\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;/exclusions\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;cglib\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;cglib-nodep\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.2.2\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; \u0026lt;build\u0026gt; \u0026lt;finalName\u0026gt;hive\u0026lt;/finalName\u0026gt; \u0026lt;/build\u0026gt; \u0026lt;repositories\u0026gt; \u0026lt;repository\u0026gt; \u0026lt;id\u0026gt;cloudera\u0026lt;/id\u0026gt; \u0026lt;url\u0026gt;https://repository.cloudera.com/artifactory/cloudera-repos\u0026lt;/url\u0026gt; \u0026lt;releases\u0026gt; \u0026lt;enabled\u0026gt;true\u0026lt;/enabled\u0026gt; \u0026lt;/releases\u0026gt; \u0026lt;snapshots\u0026gt; \u0026lt;enabled\u0026gt;false\u0026lt;/enabled\u0026gt; \u0026lt;/snapshots\u0026gt; \u0026lt;/repository\u0026gt; \u0026lt;repository\u0026gt; \u0026lt;id\u0026gt;people.apache.snapshots\u0026lt;/id\u0026gt; \u0026lt;url\u0026gt;http://repository.apache.org/content/groups/snapshots-group/\u0026lt;/url\u0026gt; \u0026lt;releases\u0026gt; \u0026lt;enabled\u0026gt;false\u0026lt;/enabled\u0026gt; \u0026lt;/releases\u0026gt; \u0026lt;snapshots\u0026gt; \u0026lt;enabled\u0026gt;true\u0026lt;/enabled\u0026gt; \u0026lt;/snapshots\u0026gt; \u0026lt;/repository\u0026gt; \u0026lt;/repositories\u0026gt; \u0026lt;/project\u0026gt; Create HiveTest.java\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.coinidea; import java.sql.*; public class HiveTest { /* Start server: hive --service hiveserver2 --hiveconf hive.server2.thrift.port=10000 */ private static String driverName = \u0026#34;org.apache.hive.jdbc.HiveDriver\u0026#34;; /** * @param args * @throws SQLException */ public static void main(String[] args) throws SQLException { try { Class.forName(driverName); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } //replace \u0026#34;hive\u0026#34; here with the name of the user the queries should run as Connection con = DriverManager.getConnection(\u0026#34;jdbc:hive2://192.168.*.*:10000/default\u0026#34;, \u0026#34;hive\u0026#34;, \u0026#34;hive\u0026#34;); Statement stmt = con.createStatement(); String table_user = \u0026#34;test.user\u0026#34;; String user_sql = \u0026#34;select uri from \u0026#34; + table_user + \u0026#34; limit 10\u0026#34;; System.out.println(\u0026#34;Running: \u0026#34; + user_sql); ResultSet users = stmt.executeQuery(user_sql); while (users.next()) { System.out.println(\u0026#34;USER:\u0026#34; + users.getString(1)); } stmt.close(); } } Before running HiveTest, you need to start HiveServer2\n1 hive --service hiveserver2 --hiveconf hive.server2.thrift.port=10000 ","date":"2016-04-28T07:11:02Z","permalink":"https://blog.coinidea.com/en/p/java-connecting-to-and-running-hive-via-jdbc/","title":"[Java] Connecting to and Running Hive via JDBC"},{"content":"IntelliJ IDEA Version: 15.0 I had been using Eclipse/MyEclipse for Java and Android development, and heard that IntelliJ IDEA is also an excellent IDE. It is a product from the company behind PHPStorm.\nWhat is Maven? I only recently started using it. I hadn\u0026rsquo;t written much Java before \u0026ndash; I did some JSP during my undergraduate years and wrote some Android code recently. But Java has a rather serious issue with library dependency management, and there are so many library versions. I remember frequently downloading libraries from various places online, then using build path to add external libraries. This approach leads to messy library management, poor version control, and makes it difficult to share code. Maven is a project management tool that handles library versions and dependencies very well.\nCreating a Maven Project File -\u0026gt; New -\u0026gt; Project, select Maven.\nIf you need to specify the project type such as app or webapp, check \u0026ldquo;Create from archetype\u0026rdquo; and select the corresponding type.\nEnter GroupId and ArtifactId.\nMy understanding is that GroupId is the name of the overall parent project or organization the project belongs to, and ArtifactId is the name and purpose of the current project.\nEnter the project folder name and path\nAfter creating the Maven project, click \u0026ldquo;Enable Auto-Import\u0026rdquo; on the main screen. Otherwise, Maven-managed libraries won\u0026rsquo;t be automatically imported into the project and will need to be imported manually, which is inconvenient.\nView -\u0026gt; Tool Window -\u0026gt; Maven Projects will open a tool window. The main functions you\u0026rsquo;ll use are clean and compile.\nYou can use the built-in Maven or your own downloaded Maven. If you want to use your own, go to File -\u0026gt; Settings.\nConfigure the project pom file\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;project xmlns=\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\u0026#34;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;groupId\u0026gt;com.coinidea\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;maven.text\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.0-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;!-- properties version --\u0026gt; \u0026lt;properties\u0026gt; \u0026lt;spring.version\u0026gt;4.2.5.RELEASE\u0026lt;/spring.version\u0026gt; \u0026lt;hadoop.version\u0026gt;2.5.0-cdh5.3.2\u0026lt;/hadoop.version\u0026gt; \u0026lt;hive.version\u0026gt;0.13.1-cdh5.3.2\u0026lt;/hive.version\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;dependencies\u0026gt; \u0026lt;!-- junit --\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;junit\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;junit\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.8.1\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--spring--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-context\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-core\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-web\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-webmvc\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-test\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;${spring.version}\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; \u0026lt;!-- Specify maven repository --\u0026gt; \u0026lt;repositories\u0026gt; \u0026lt;repository\u0026gt; \u0026lt;id\u0026gt;people.apache.snapshots\u0026lt;/id\u0026gt; \u0026lt;url\u0026gt;http://repository.apache.org/content/groups/snapshots-group/\u0026lt;/url\u0026gt; \u0026lt;releases\u0026gt; \u0026lt;enabled\u0026gt;false\u0026lt;/enabled\u0026gt; \u0026lt;/releases\u0026gt; \u0026lt;snapshots\u0026gt; \u0026lt;enabled\u0026gt;true\u0026lt;/enabled\u0026gt; \u0026lt;/snapshots\u0026gt; \u0026lt;/repository\u0026gt; \u0026lt;/repositories\u0026gt; \u0026lt;/project\u0026gt; Click clean and compile, and the libraries will be downloaded to your local Maven repository and automatically imported into the current project.\n","date":"2016-04-28T07:04:11Z","permalink":"https://blog.coinidea.com/en/p/java-creating-a-maven-project-in-intellij-idea/","title":"[Java] Creating a Maven Project in IntelliJ IDEA"},{"content":"When configuring Git to use a proxy, you can use the following commands to set and remove the proxy:\nConfiguring Git Proxy To configure HTTP and HTTPS proxies for Git, use the following commands:\n1 2 3 4 5 # Configure HTTP proxy git config --global http.proxy http://127.0.0.1:1080 # Configure HTTPS proxy git config --global https.proxy https://127.0.0.1:1080 Removing Git Proxy Configuration To remove the proxy settings, use the following commands:\n1 2 3 4 5 # Remove HTTP proxy git config --global --unset http.proxy # Remove HTTPS proxy git config --global --unset https.proxy Explanation git config --global http.proxy \u0026lt;proxy-url\u0026gt;: Configure the global HTTP proxy. git config --global https.proxy \u0026lt;proxy-url\u0026gt;: Configure the global HTTPS proxy. git config --global --unset http.proxy: Remove the global HTTP proxy configuration. git config --global --unset https.proxy: Remove the global HTTPS proxy configuration. With these commands, you can easily enable or disable Git proxy settings as needed.\n","date":"2016-04-09T08:02:47Z","permalink":"https://blog.coinidea.com/en/p/git-configuring-and-removing-git-proxy/","title":"[Git] Configuring and Removing Git Proxy"},{"content":"As SAE (Sina App Engine) pricing continues to rise, cost savings become increasingly important. Starting March 2016, shared MySQL also began incurring charges, making it important for multiple applications to share a single MySQL instance.\nSteps to Share a Single MySQL Across Multiple Applications Assume you have multiple applications (APP1, APP2, APP3): Only APP1 retains the shared MySQL, while APP2 and APP3 will use APP1\u0026rsquo;s MySQL. Export APP2 and APP3\u0026rsquo;s MySQL databases as backups, then delete APP2 and APP3\u0026rsquo;s MySQL instances. This way, APP2 and APP3\u0026rsquo;s MySQL will be uninitialized and no longer incur charges. Import APP2 and APP3\u0026rsquo;s database files (*.sql) into APP1\u0026rsquo;s MySQL. Before importing, make sure table names don\u0026rsquo;t conflict. In APP1\u0026rsquo;s MySQL settings, click Cross-Application Authorization to select applications under your account or other accounts. Authorize APP2 and APP3 here. Write a script to display APP1\u0026rsquo;s MySQL connection information for the authorized applications APP2 and APP3 to use (this will expose database credentials, so proceed with caution and delete the script promptly). Related code:\n1 2 3 4 5 6 7 8 9 \u0026lt;?php header(\u0026#34;Content-type:text/html;charset=utf-8\u0026#34;); echo \u0026#34;Username :\u0026#34;.SAE_MYSQL_USER.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;Password :\u0026#34;.SAE_MYSQL_PASS.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;Master Host:\u0026#34;.SAE_MYSQL_HOST_M.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;Slave Host :\u0026#34;.SAE_MYSQL_HOST_S.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;Port :\u0026#34;.SAE_MYSQL_PORT.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; echo \u0026#34;Database :\u0026#34;.SAE_MYSQL_DB.\u0026#34;\u0026lt;br\u0026gt;\u0026#34;; ?\u0026gt; Run the script: The page will display APP1\u0026rsquo;s MySQL information. Use this information in your other applications (such as APP2 and APP3) to connect to the database. Notes Security: Since the script exposes sensitive information such as database username and password, make sure to delete the script promptly after use to prevent information leakage. Table name conflicts: When importing APP2 and APP3\u0026rsquo;s database files into APP1\u0026rsquo;s MySQL, ensure there are no table name conflicts. If conflicts exist, consider renaming tables before importing. Authorization management: When performing cross-application authorization on the SAE management platform, only authorize necessary applications to avoid unnecessary permission exposure. Through these steps, you can effectively reduce SAE MySQL costs while ensuring multiple applications can access the shared database normally.\n","date":"2016-04-09T07:50:12Z","permalink":"https://blog.coinidea.com/en/p/sae-sae-mysql-cross-application-authorization/","title":"[SAE] SAE MySQL Cross-Application Authorization"},{"content":"Since Node.js is non-blocking, single-process, and single-threaded, once an exception is thrown, the entire service stops, making it very unstable. Here are the solutions:\nMake the program robust: Wrap all potentially exception-prone areas with try { } catch(){ }. Express error handling mechanism: As a commonly used Node.js framework, Express has its own error handling mechanism. 1 2 3 4 5 6 // Express\u0026#39; errorHandler function errorHandler(err, req, res, next) { console.error(err.stack); res.status(500).send(\u0026#39;Something broke!\u0026#39;); } app.use(errorHandler); Use the domain module: First install the domain module with npm install domain 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // Domain exception handling const domain = require(\u0026#39;domain\u0026#39;); app.use(function(req, res, next) { var reqDomain = domain.create(); reqDomain.on(\u0026#39;error\u0026#39;, function(err) { console.log(err.stack); res.statusCode = 500; res.end(err.message + \u0026#39;\\n\u0026#39;); reqDomain.dispose(); }); reqDomain.add(req); reqDomain.add(res); reqDomain.run(next); }); Use forever to start app.js: Forever acts as a daemon process for Node.js that can start, stop, and restart your app. 1 forever start app.js Through these methods, you can improve the stability of Node.js services and prevent the entire service from crashing due to uncaught exceptions.\n","date":"2016-03-10T09:30:18Z","permalink":"https://blog.coinidea.com/en/p/node.js-exception-handling-in-node.js-express/","title":"[Node.js] Exception Handling in Node.js Express"},{"content":" 1 2 3 4 5 \u0026lt;?php $memcache_obj = memcache_connect(\u0026#39;127.0.0.1\u0026#39;, 11211); $memcache_obj-\u0026gt;add(\u0026#34;name\u0026#34;, \u0026#34;test\u0026#34;); echo $memcache_obj-\u0026gt;get(\u0026#34;name\u0026#34;); ?\u0026gt; If you encounter issues using this code, make sure of the following:\nIs the Memcache service running: Ensure your Memcache service is running on 127.0.0.1 at port 11211. Is the PHP Memcache extension installed and enabled: Make sure you have installed and enabled the PHP Memcache extension. You can install the Memcache extension with the following command:\n1 sudo apt-get install php-memcache And enable the extension in your php.ini file:\n1 extension=memcache.so Restart your web server to apply changes:\n1 sudo service apache2 restart Or, if you\u0026rsquo;re using Nginx:\n1 sudo service nginx restart If you\u0026rsquo;re using memcached instead of memcache, make sure to use the correct extension and functions:\n1 2 3 4 5 6 \u0026lt;?php $memcached = new Memcached(); $memcached-\u0026gt;addServer(\u0026#39;127.0.0.1\u0026#39;, 11211); $memcached-\u0026gt;set(\u0026#34;name\u0026#34;, \u0026#34;test\u0026#34;); echo $memcached-\u0026gt;get(\u0026#34;name\u0026#34;); ?\u0026gt; In this case, you need to install the php-memcached extension:\n1 sudo apt-get install php-memcached ","date":"2016-03-08T12:42:07Z","permalink":"https://blog.coinidea.com/en/p/memcache-testing-memcache-connection-with-php/","title":"[Memcache] Testing Memcache Connection with PHP"},{"content":"Some people reported that clicking doesn\u0026rsquo;t respond. I\u0026rsquo;ve tested this on both Chrome and IE and it works:\nI think the likely reason is that jQuery was not included. I\u0026rsquo;ve now added jQuery from a CDN and updated the code to:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; \u0026lt;script src=\u0026#34;https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js\u0026#34; type=\u0026#34;text/javascript\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;title\u0026gt;\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div id=\u0026#39;div1\u0026#39;\u0026gt;Put the content to print here\u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;div2\u0026#34;\u0026gt;div2 content\u0026lt;/div\u0026gt; \u0026lt;a href=\u0026#34;javascript:printHTML(\u0026#39;#div1\u0026#39;)\u0026#34; target=\u0026#34;_self\u0026#34;\u0026gt;Print\u0026lt;/a\u0026gt; \u0026lt;script language=\u0026#34;javascript\u0026#34;\u0026gt; function printHTML(page) { var bodyHTML = window.document.body.innerHTML; window.document.body.innerHTML = $(page).html(); window.print(); window.document.body.innerHTML = bodyHTML; } \u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Original Javascript code, requires jQuery:\n1 2 3 4 5 6 function printHTML(page) { var bodyHTML = window.document.body.innerHTML; window.document.body.innerHTML = $(page).html(); window.print(); window.document.body.innerHTML = bodyHTML; } ","date":"2016-03-01T09:17:03Z","permalink":"https://blog.coinidea.com/en/p/javascript-calling-the-printer-from-a-web-page/","title":"[Javascript] Calling the Printer from a Web Page"},{"content":"Based on UEditor, this implements dynamic loading and hiding of UEditor.\nGithub: https://github.com/hujiulin/UEditorComponent\n1. Initial Page 2. Click the Left DIV 3. Click the Right DIV 4. Click an Empty Area on the Page ","date":"2016-02-26T09:31:29Z","permalink":"https://blog.coinidea.com/en/p/javascript-dynamic-loading-and-hiding-of-ueditor/","title":"[Javascript] Dynamic Loading and Hiding of UEditor"},{"content":"When inserting data into an already partitioned table, you may encounter this error:\n1 Need to specify partition columns because the destination table is partition The reason is that you need to specify the partition field values in the insert statement.\nFor example:\nCreate Table Statements: 1 2 3 4 5 6 7 8 9 CREATE TABLE test ( starttime STRING, endtime STRING, title STRING ) PARTITIONED BY (username STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0026#39;|\u0026#39; STORED AS TEXTFILE; 1 2 3 4 5 6 7 8 9 CREATE TABLE test2 ( starttime STRING, endtime STRING, title STRING ) PARTITIONED BY (username STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0026#39;|\u0026#39; STORED AS TEXTFILE; Insert Statement: 1 2 INSERT INTO TABLE test PARTITION(username=\u0026#39;admin\u0026#39;) SELECT starttime, endtime, title FROM test2 WHERE username = \u0026#39;admin\u0026#39;; ","date":"2016-02-23T13:36:11Z","permalink":"https://blog.coinidea.com/en/p/hive-need-to-specify-partition-columns-because-the-destination-table-is-partitioned/","title":"[Hive] Need to Specify Partition Columns Because the Destination Table Is Partitioned"},{"content":"Apache Configuration Download the mod_flvx.so and mod_h264_streaming.so modules.\nNote: Make sure the x86/x64 versions of Apache and the modules match [the modules below are for Apache x86 2.2 and earlier].\nDownload link: http://pan.baidu.com/s/1dEzYX4d Password: jb0i\nEdit apache\\conf\\httpd.conf, find LoadModule, and add the following at the end of (or near) the LoadModule section:\n1 2 3 4 LoadModule flvx_module modules/mod_flvx.so AddHandler flv-stream .flv LoadModule h264_streaming_module modules/mod_h264_streaming.so AddHandler h264-streaming.extensions .mp4 Restart Apache. If Apache fails to start, verify that the module versions match your Apache version.\nVideo Playback Example Download ckplayer\nAny web video player will work. This example uses ckplayer. Download link:\nhttp://www.ckplayer.com/\nConfiguration guide:\nhttp://www.ckplayer.com/tool/flashvars.htm\nPlace the ckplayer folder in the website root directory, and place the sample video example.flv in the website root directory.\nCreate video.html with the following code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026lt;html\u0026gt; \u0026lt;meta charset=\u0026#34;utf8\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;Streaming Video Playback\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div id=\u0026#34;a1\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script type=\u0026#34;text/javascript\u0026#34; src=\u0026#34;/ckplayer/ckplayer.js\u0026#34; charset=\u0026#34;utf-8\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;script type=\u0026#34;text/javascript\u0026#34;\u0026gt; var flashvars={ f:\u0026#39;http://localhost/example.flv\u0026#39;, c:0 }; var params={bgcolor:\u0026#39;#FFF\u0026#39;,allowFullScreen:true,allowScriptAccess:\u0026#39;always\u0026#39;,wmode:\u0026#39;transparent\u0026#39;}; CKobject.embedSWF(\u0026#39;/ckplayer/ckplayer.swf\u0026#39;,\u0026#39;a1\u0026#39;,\u0026#39;ckplayer_a1\u0026#39;,\u0026#39;600\u0026#39;,\u0026#39;400\u0026#39;,flashvars,params); \u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Open a browser and visit http://localhost/video.html. You should be able to drag the video scrollbar.\nChrome result:\nIE result:\n\u0026mdash;-Update 20160106\u0026mdash;-\nThe previous test had issues because the FLV file was too small, so it was likely downloaded locally before playback.\nThe correct way to verify Apache streaming is:\nPrepare a larger MP4/FLV file and replace the video URL above;\nOpen Chrome (recommended), and enter http://localhost/example.mp4?start=10;\nIf the video starts playing from the 10-second mark and supports seeking, the Apache configuration is successful.\nThe ckplayer mentioned above still requires waiting for the download to complete before sequential playback. It is recommended to use video.js instead, though it requires HTML5 browser support.\nHTML code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;link href=\u0026#34;/video-js/video-js.css\u0026#34; rel=\u0026#34;stylesheet\u0026#34;\u0026gt; \u0026lt;!-- If you\u0026#39;d like to support IE8 --\u0026gt; \u0026lt;script src=\u0026#34;/video-js/ie8/videojs-ie8.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;video id=\u0026#34;my-video\u0026#34; class=\u0026#34;video-js\u0026#34; controls preload=\u0026#34;auto\u0026#34; width=\u0026#34;auto\u0026#34; height=\u0026#34;auto\u0026#34; poster=\u0026#34;http://vjs.zencdn.net/v/oceans.png\u0026#34; data-setup=\u0026#34;{}\u0026#34;\u0026gt; \u0026lt;source src=\u0026#34;/video/example.mp4\u0026#34; type=\u0026#39;video/mp4\u0026#39;\u0026gt; \u0026lt;p class=\u0026#34;vjs-no-js\u0026#34;\u0026gt; To view this video please enable JavaScript, and consider upgrading to a web browser that \u0026lt;a href=\u0026#34;http://videojs.com/html5-video-support/\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;supports HTML5 video\u0026lt;/a\u0026gt; \u0026lt;/p\u0026gt; \u0026lt;/video\u0026gt; \u0026lt;script src=\u0026#34;/video-js/video.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; After testing, the video can be seeked to any position and played even before it is fully loaded. With this, Apache has achieved pseudo-streaming video playback.\n","date":"2016-01-05T10:00:00Z","permalink":"https://blog.coinidea.com/en/p/apache-configuring-apache-for-streaming-media/","title":"[Apache] Configuring Apache for Streaming Media"},{"content":"Just like that, 2015 is gone, and today is the first day of 2016. The most fulfilling thing I did today was donating a big bag of clothes I had accumulated over my college years to the school. I\u0026rsquo;m a strange person \u0026ndash; I often don\u0026rsquo;t throw away old things, which makes moving extremely troublesome. I once heard about a concept called organizing through \u0026ldquo;cut, let go, and separate.\u0026rdquo; So I tried discarding my old junk and clutter to reorganize my life.\nIt\u0026rsquo;s been about half a year since I started working and entered the workforce. I thought I was well-prepared, but I still struggled. It\u0026rsquo;s like estimating project scope \u0026ndash; there\u0026rsquo;s a law that says no matter how you estimate the workload, you\u0026rsquo;ll always underestimate by one-third of the time, even if you account for this very law.\nIn my 2014 year-end review, I mentioned:\nI hope to accomplish the following items in 2015:\nTravel\n1.1 Go to Harbin [Done]\n1.2 Go to Tibet\n1.3 Go to Yunnan [Done]\nContinue learning and sharing technical knowledge on my personal blog, and write high-quality posts [Done, should be able to keep it up, though quality will improve gradually].\nFortunately, the blog\u0026rsquo;s daily UV has grown from 1-2 visitors to over ten. A couple of posts have pretty high traffic, and one of them currently appears on the first page of Baidu search results for the keyword \u0026ldquo;Yii Redis,\u0026rdquo; which makes me very happy \u0026ndash; even though it\u0026rsquo;s the last result on the first page.\nContinue writing higher quality code and contribute on GitHub, hoping one of my projects can reach 100 Stars.\nThis one failed. My highest cumulative Stars on GitHub is only around 20. I hope to work harder.\nOpen-source a portal system based on ThinkPHP [Done, but not open-sourced].\nThink about my future and focus deeply on a specific technology.\nThe road ahead is long; I shall search high and low.\nRead some quality books:\n6.1 Wu Jun\u0026rsquo;s \u0026ldquo;Civilization and Enlightenment\u0026rdquo;\nPurchased but didn't read much. 6.2 Malcolm Gladwell\u0026rsquo;s \u0026ldquo;David and Goliath\u0026rdquo;\nNot completed. 6.3 Finish \u0026ldquo;High Output Management\u0026rdquo; by Andrew Grove\nNot completed. 6.4 Finish \u0026ldquo;Effective C++\u0026rdquo;\nNot completed. 6.5 \u0026ldquo;Predictably Irrational\u0026rdquo; [Done]\nStudy English properly and aim for independent travel abroad.\nNot completed.\nRedo all LeetCode problems from scratch.\nPartially completed, solved some problems using PHP.\nBeyond that, the things that made me happiest:\nRead some books: \u0026ldquo;Zero to One,\u0026rdquo; \u0026ldquo;Don\u0026rsquo;t Make Me Think,\u0026rdquo; \u0026ldquo;The First Line of Code: Android\u0026rdquo; CoinIdea got a nice redesign [designed independently, using AI for graphics] \u0026ndash; feeling better and better about it. While my patience, temper, and temperament still have room for improvement, there has been some progress. I\u0026rsquo;m on the path to learning Android. Gained new insights into PHP and MySQL. I typed so many words: OK, now let me look ahead to 2016. This is bound to be a critical year. It seems like something big happens in my life every 4-5 years. Just Face It.\nPractice English and pass the TOEIC exam. Get started with iOS, deepen Android learning and application; advance in PHP and MySQL, and develop an OA system using Yii. I hope the people around me pass their English exams smoothly. May my parents stay healthy. Read \u0026ldquo;Civilization and Enlightenment.\u0026rdquo; Finish reading \u0026ldquo;PHP, MySQL, and Web Development\u0026rdquo; and \u0026ldquo;PHP Advanced and Object-Oriented Programming.\u0026rdquo; Hope to pick up C# and WorldWind again. Make some breakthroughs in data visualization. Hope that CoinIdea, which I maintain in my spare time, keeps getting better. I hope to achieve the unfulfilled wishes from last year. Not being greedy \u0026ndash; just these. Number four is a blessing.\n","date":"2016-01-01T13:56:14Z","permalink":"https://blog.coinidea.com/en/p/year-end-review-my-2015/","title":"[Year-End Review] My 2015"},{"content":"Downloading ZendGuard Official download link: http://www.zend.com/en/products/guard/downloads#Windows\nRegistration is required before downloading. I downloaded Zend Guard 6.0. Simply double-click to run the installer.\nThe latest version is 7.0. If you want to download an earlier version, click \u0026ldquo;\u0026gt;Download here\u0026rdquo; and a list of older versions will appear below the current page.\nDownloading PHP Official download links: http://php.net/downloads.php | http://php.net/releases/\nMy current version: http://windows.php.net/download/#php-5.4\nPHP typically releases two types of builds for each version: Thread Safe and Non Thread Safe.\nImportant note: ZendGuard only supports Non Thread Safe builds. So please download the Non Thread Safe version of PHP.\nConfiguring PHP \u0026ndash; ZendLoader.dll Download ZendLoader.dll\nOfficial download link: http://www.zend.com/en/products/loader/downloads#Windows\nRegistration is required before downloading. Similar to ZendGuard, make sure to select the ZendLoader version that matches your PHP version.\nCopy ZendLoader.dll to the PHP [PHP root directory]\\ext\\ folder.\nRename php.ini-development or php.ini-production to php.ini,\nand add the following content to php.ini:\n1 2 3 4 5 6 7 8 9 10 11 12 13 zend_extension=\u0026#34;./ext/ZendLoader.dll\u0026#34; ; Enables loading encoded scripts. The default value is On zend_loader.enable=1 ; Disable license checks (for performance reasons) zend_loader.disable_licensing=0 ; The Obfuscation level supported by Zend Guard Loader. The levels are detailed in the official Zend Guard Documentation. 0 - no obfuscation is enabled zend_loader.obfuscation_level_support=3 ; Path to where licensed Zend products should look for the product license. For more information on how to create a license file, see the Zend Guard User Guide zend_loader.license_path= Creating PHP Code Create an input folder, and inside it create test.php.\nCode:\n1 2 3 4 5 \u0026lt;?php date_default_timezone_set(\u0026#34;Asia/shanghai\u0026#34;); echo \u0026#34;Thanks ZendGuard!\\n\u0026#34;; echo \u0026#34;Now datetime is \u0026#34;.date(\u0026#34;Y-m-d h:i:s\u0026#34;).\u0026#34;\\n\u0026#34;; ?\u0026gt; The above code outputs:\nThanks ZendGuard\nNow datetime is [current time].\nInstalling ZendGuard and Creating a Project ZendGuard has a straightforward installer. After installation, launch it and you\u0026rsquo;ll see:\nCreate a new Zend Guard Project. Set the output directory to the output folder.\nAdd the input folder as the input directory. Select the PHP version.\nClick A new test.php is generated in the output folder. Opening it reveals garbled content (the encrypted code). Running Source Code and Encrypted Code Running the source code:\nRunning the encrypted code:\nWith this, you can now use ZendGuard to encrypt PHP code.\n","date":"2015-12-29T07:28:22Z","permalink":"https://blog.coinidea.com/en/p/php-encrypting-php-with-zendguard/","title":"[PHP] Encrypting PHP with ZendGuard"},{"content":"Version Details PHP: 5.3\nPHPUnit\nThinkPHP 3.1.3\nIDE: PHPStorm 10 (recommended)\nConfiguring PHPUnit in PHPStorm See the blog post:\nhttp://blog.coinidea.com/web开发/php-1088.html\nThinkPHP Deployment Official code download:\nhttp://www.thinkphp.cn/down.html\nSite initialization:\nhttp://www.thinkphp.cn/info/60.html\nTest Cases In this example, the index.php in the root directory is configured as follows:\n1 2 3 4 5 6 7 \u0026lt;?php define(\u0026#39;APP_NAME\u0026#39;, \u0026#39;example\u0026#39;); define(\u0026#39;APP_PATH\u0026#39;, \u0026#39;../example/\u0026#39;); define(\u0026#39;APP_PHPUNIT\u0026#39;, false); define(\u0026#39;APP_DEBUG\u0026#39;, true); require(\u0026#39;../ThinkPHP/ThinkPHP.php\u0026#39;); ?\u0026gt; After the first visit, the following directory structure is generated:\nCreate a new folder named \u0026ldquo;Testcase\u0026rdquo; in the example site.\nTesting the Model Create HelloModel.class.php:\n1 2 3 4 5 6 7 8 9 \u0026lt;?php class HelloModel extends Model { public function sayHello() { print \u0026#39;Hello\u0026#39;; return \u0026#39;Hello\u0026#39;; } } Create a Test.php file in the Test folder as the PHPUnit test file. Note that you need to require ThinkPHP to initialize the framework environment. Also, in Think.class.php, modify the\nstart() function by changing App::run() to !APP_PHPUNIT \u0026amp;\u0026amp; App::run();\nThis distinguishes between site runtime and test case execution.\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026lt;?php define(\u0026#39;APP_NAME\u0026#39;, \u0026#39;example\u0026#39;); define(\u0026#39;APP_PATH\u0026#39;, \u0026#39;./../../example/\u0026#39;); define(\u0026#39;APP_PHPUNIT\u0026#39;, true); require(\u0026#39;./../../ThinkPHP/ThinkPHP.php\u0026#39;); class TestSayHello extends PHPUnit_Framework_TestCase { public function setUp() { } public function tearDown(){ } } Add a test case in TestSayHello:\n1 2 3 4 5 public function testHelloModel() { $hello = D(\u0026#39;Hello\u0026#39;); $this-\u0026gt;assertTrue($hello-\u0026gt;sayHello(\u0026#39;Hello\u0026#39;) == \u0026#39;Hello\u0026#39;); } Testing the Action Modify IndexAction.class.php as follows:\n1 2 3 4 5 6 7 8 9 \u0026lt;?php class IndexAction extends Action { public function index() { $hello = D(\u0026#34;Hello\u0026#34;); return $hello-\u0026gt;sayHello(); } } Browser access to Index:\nAdd a test case in TestSayHello:\n1 2 3 4 5 public function testHelloAction() { $hello = new IndexAction(); $this-\u0026gt;assertTrue($hello-\u0026gt;index() == \u0026#39;Hello\u0026#39;); } Results Running Test.php produces the following result:\nTests passed. At this point, unit testing has been successfully added to ThinkPHP.\npoisonbian 2016/05/10 14:57 I tried following this guide and found that the model couldn\u0026rsquo;t be used, and custom functions in the Common directory were not loaded. After some investigation, I think adding the APP_PHPUNIT check in Think.class.php is not ideal. It would be better to add it in App.class.php instead: !APP_PHPUNIT \u0026amp;\u0026amp; App::exec();\n","date":"2015-12-10T14:19:57Z","permalink":"https://blog.coinidea.com/en/p/php-configuring-phpunit-for-thinkphp/","title":"[PHP] Configuring PHPUnit for ThinkPHP"},{"content":"PHPUnit Installation and Sample Test Many people online recommend installing via PEAR. I tried various methods from different blog posts, but all failed. The method that worked for me is more straightforward: Download link:\nhttps://phpunit.de/index.html\nThe download is a .phar PHP extension. Download the PHPUnit version that matches your PHP version.\nFollow the instructions at https://phpunit.de/manual/current/en/installation.html#installation.phar.windows step by step.\nDownload PHPUnit.phar to a folder, for example: C:\\bin\\ Add this folder C:\\bin\\ to the Path environment variable In the command line, navigate to C:\\bin and enter: echo @php \u0026quot;%~dpophpunit.phar\u0026quot;%*\u0026gt;phpunit.cmd In any command line location, enter:\n1 phpunit --version You should see:\nAt this point, PHPUnit is successfully installed.\nTest Example: SayHello.php\n1 2 3 4 5 6 7 8 9 10 11 \u0026lt;?php class SayHello { public function printHello() { echo \u0026#39;Hello\u0026#39;; return \u0026#39;Hello\u0026#39;; } } ?\u0026gt; TestSayHello.php\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026lt;?php require_once \u0026#39;SayHello.php\u0026#39;; class TestSayHello extends PHPUnit_Framework_TestCase { public function setUp() { } public function tearDown() { } public function testConnectionIsValid() { $hi = new SayHello(); $this-\u0026gt;assertTrue($hi-\u0026gt;printHello() == \u0026#39;Hello\u0026#39;); } } ?\u0026gt; The SayHello class prints \u0026ldquo;Hello\u0026rdquo; to the screen and returns \u0026ldquo;Hello\u0026rdquo;.\nTestSayHello verifies whether the SayHello class correctly returns the \u0026ldquo;Hello\u0026rdquo; string.\nRun it in the command line, and the test passes.\nConfiguring PHPUnit in PHPStorm Older versions of PHPStorm may not support PHPUnit well and will throw:\nWarning: require_once(PHPUnit/Runner/Version.php)\nSee:\nhttp://stackoverflow.com/questions/30278588/phpstorm-via-phpunit-phar-warning-require-oncephpunit-runner-version-php\nThis article uses PHPStorm 10. Download link:\nhttps://www.jetbrains.com/phpstorm/?fromMenu\nOpen the two files from earlier Open Settings: File =\u0026gt; Settings Configure PHP version:\nConfigure PHPUnit\nSample Test\nSelect TestSayHello and run it directly. The result:\n","date":"2015-12-04T14:45:19Z","permalink":"https://blog.coinidea.com/en/p/php-phpunit-installation-configuration-and-examples/","title":"[PHP] PHPUnit Installation, Configuration, and Examples"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 \u0026lt;?php class Solution { public function containsDuplicate($nums) { $hashTable = array(); foreach ($nums as $num) { if (!array_key_exists($num,$hashTable)) { $hashTable[$num] = 1; } else { return false; } } return true; } } $solution = new Solution(); echo $solution-\u0026gt;containsDuplicate(array(2,1,3,4,5,6,7,9)); ?\u0026gt; ","date":"2015-12-01T10:06:29Z","permalink":"https://blog.coinidea.com/en/p/leetcodephp-implementation-contains-duplicate/","title":"[LeetCode][PHP Implementation] Contains Duplicate"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026lt;?php class Solution { public function titleToNumber($s) { $num = 0; $len = strlen($s) - 1; for ($i = $len; $i \u0026gt;= 0; $i--) { $num += (ord($s[$i]) - ord(\u0026#39;A\u0026#39;) + 1) * (int)pow(26, $len - $i); } return $num; } } $solution = new Solution(); echo $solution-\u0026gt;titleToNumber(\u0026#34;AA\u0026#34;); ?\u0026gt; ","date":"2015-11-30T12:25:48Z","permalink":"https://blog.coinidea.com/en/p/leetcodephp-implementation-excel-sheet-column-number/","title":"[LeetCode][PHP Implementation] Excel Sheet Column Number"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 \u0026lt;?php class Solution { public function isAnagram($s, $t) { $s = strtolower($s); $t = strtolower($t); for ($i = 0; $i \u0026lt; 26; $i++) { $sChars[$i] = 0; $tChars[$i] = 0; } for ($i = 0; $i \u0026lt; strlen($s); $i++) { $sChars[ord($s[$i]) - ord(\u0026#39;a\u0026#39;)]++; } for ($i = 0; $i \u0026lt; strlen($t); $i++) { $tChars[ord($t[$i]) - ord(\u0026#39;a\u0026#39;)]++; } //var_dump($sChars); //var_dump($tChars); for ($i = 0; $i \u0026lt; 26; $i++) { if ($sChars[$i] != $tChars[$i]) { return false; } } return true; } } $solution = new Solution(); echo $solution-\u0026gt;isAnagram(\u0026#34;HelloWorld\u0026#34;, \u0026#34;whelloorld\u0026#34;); ?\u0026gt; ","date":"2015-11-30T12:24:46Z","permalink":"https://blog.coinidea.com/en/p/leetcodephp-implementation-valid-anagram/","title":"[LeetCode][PHP Implementation] Valid Anagram"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 \u0026lt;?php class Solution { public function addDigits($num) { while ($num \u0026gt; 10) { $tmp = 0; while ($num \u0026gt; 0) { $tmp += $num % 10; $num = intval($num / 10); } $num = $tmp; } return $num; } } $solution = new Solution(); echo $solution-\u0026gt;addDigits(381); ?\u0026gt; ","date":"2015-11-30T12:23:52Z","permalink":"https://blog.coinidea.com/en/p/leetcodephp-implementation-add-digits/","title":"[LeetCode][PHP Implementation] Add Digits"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 \u0026lt;?php class solution { public function twoSum($nums, $target) { $result = array(); for ($i = 0; $i \u0026lt; count($nums); $i++) { for ($j = 0; $j \u0026lt; count($nums); $j++) { if ($target == $nums[$i] + $nums[$j]) { $result[0] = $i + 1; $result[1] = $j + 1; return $result; } } } return $result; } } $solution = new Solution(); var_dump($solution-\u0026gt;twoSum(array(2,7,11,15), 9)); ?\u0026gt; ","date":"2015-11-30T12:22:21Z","permalink":"https://blog.coinidea.com/en/p/leetcodephp-implementation-two-sum/","title":"[LeetCode][PHP Implementation] Two Sum"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026lt;?php class Solution { public function singleNumber($nums) { $single = 0; foreach ($nums as $num) { $single ^= $num; echo $num; } return $single; } } $solution = new Solution(); echo $solution-\u0026gt;singleNumber(array(1,1,2,3,2,4,4,5,3)); ?\u0026gt; ","date":"2015-11-30T12:20:03Z","permalink":"https://blog.coinidea.com/en/p/leetcodephp-implementation-single-number/","title":"[LeetCode][PHP Implementation] Single Number"},{"content":"Requirement:\nA table contains a text field. We need to count the number of records whose text length falls into ranges [0,20], [20,40], [40,60], etc. The ranges should automatically extend to cover the maximum value.\nImplementation:\nMethod 1:\n1 2 3 4 5 6 7 select count(case when length(text) between 0 and 20 then 1 end) as text1, count(case when length(text) between 21 and 40 then 1 end) as text2, count(case when length(text) between 41 and 60 then 1 end) as text3, count(case when length(text) between 61 and 80 then 1 end) as text4, count(case when length(text) between 81 and 100 then 1 end) as text5, count(case when length(text) \u0026gt; 100 then 1 end) as text6 from table; The problem with this approach is that you need to know the max value first. As the max increases, the SQL statement gets longer and longer, and it requires manual intervention.\nMethod 2:\n1 select floor(length(text)/20) * 20, count(*) from table group by floor(length(text)/20); This method divides each text\u0026rsquo;s length by 20, floors the result, then multiplies by 20 to get a grouping key. Using this key for GROUP BY gives us the final result. Without any loops, this simple statement elegantly solves the automatic range-based statistics problem.\n","date":"2015-11-18T07:45:26Z","permalink":"https://blog.coinidea.com/en/p/hive-hive-sql-range-based-statistics/","title":"[Hive] Hive SQL Range-Based Statistics"},{"content":"\nGrunt is a front-end automation tool, and there are plenty of blog posts on the internet about how to install and use it:\nhttp://www.cnblogs.com/wangfupeng1988/p/4561993.html\nhttp://www.cnblogs.com/lhb25/archive/2013/01/24/grunt-for-javascript-project-a.html\nSince Grunt installation depends on Node.js, this article mainly covers solutions for when \u0026ldquo;npm install grunt\u0026rdquo; downloads slowly or fails entirely. The fix is simple: specify the download registry by appending -registry \u0026quot;http://registry.npmjs.org\u0026quot; to the command, which changes the default from HTTPS to HTTP. Alternatively, Chinese internet companies like Taobao also provide registries that you can search for and use.\nFor example:\n1 install grunt --save-dev -registry \u0026#34;http://registry.npmjs.org\u0026#34; ","date":"2015-11-15T03:37:01Z","permalink":"https://blog.coinidea.com/en/p/slow-or-failed-grunt-downloads/","title":"Slow or Failed Grunt Downloads"},{"content":"Some people say this book is quite outdated, but I still made a point to read through it recently.\nHere is a summary, as shown in the diagram below:\nSince I have also been working in web development for a long time, there were actually many tips worth noting throughout the book. We may understand the big principles, but when it comes to actually implementing them, they are easy to overlook.\nAfter finishing this book, I felt like I had given my own website a round of optimization. Perhaps the one word I took away from it is \u0026ldquo;usability.\u0026rdquo; I believe that in a few years, I will have an even deeper appreciation for it.\n","date":"2015-11-09T04:48:46Z","permalink":"https://blog.coinidea.com/en/p/book-notes-dont-make-me-think/","title":"[Book Notes] Don't Make Me Think"},{"content":"\n","date":"2015-11-05T05:14:08Z","permalink":"https://blog.coinidea.com/en/p/android-weekly-study-report-6-complete-data-storage-solutions-a-detailed-guide-to-persistence/","title":"[Android] Weekly Study Report 6: Complete Data Storage Solutions — A Detailed Guide to Persistence"},{"content":"User Management Recently I have been setting up a CDH cluster of about 10 nodes. The cluster uses 10 CentOS 6.7 servers, so I frequently need to use Linux user management commands.\nChange password\n1 passwd Enter the new password and confirm it. For security, the password should include uppercase and lowercase letters, numbers, and special characters. Linux will also remind you of the password rules.\nSwitch user\n1 su hdfs This switches to the hdfs user.\nAlternatively, without switching users, you can execute a command or access a file with a specific user\u0026rsquo;s permissions:\n1 su hdfs hadoop fs -mkdir /user/hdfs/test This creates a test directory at /user/hdfs/ on the cluster using hdfs user permissions.\nFile Management Create a directory\n1 mkdir [folder] Create a file\n1 touch/vi [filename] Timezone Selection Follow the prompts to select a timezone, then enter the suggested command.\n1 tzselect Modify the timezone in the clock file.\n1 2 vi /etc/sysconfig/clock ZONE=\u0026#34;Asia/Shanghai\u0026#34; Delete the existing localtime and create a new one.\n1 2 rm /etc/localtime ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime Run Commands at Startup Edit the rc.local file\n1 vi /etc/rc.local Start the NTP Service to Sync with a Time Server on the LAN 1 2 service ntpd start /usr/sbin/ntpdate 192.168.34.115 [To be continued\u0026hellip;]\n","date":"2015-10-17T08:24:07Z","permalink":"https://blog.coinidea.com/en/p/linux-summary-of-linux-commands/","title":"[Linux] Summary of Linux Commands"},{"content":"When a user opens a browser and enters a URL:\nThe client checks whether there is an IP address cached for that URL. If not, it sends a request to the nearest DNS server for domain name resolution, querying up to the root DNS server if necessary. Once the query succeeds, the result is returned to the client.\nThe browser sends the request to the web server at the IP address corresponding to the URL.\nThis server may be a single standalone server, a lightweight load balancer, or a cluster.\nIf it is a load balancer or cluster, the servers internally synchronize based on timestamps to ensure the data is up to date; if not, synchronization is performed.\nIf the request involves application-level calls, the request is forwarded to the application server, which returns the result to the web server.\nThe web server executes programs written in the relevant dynamic languages, communicates with database servers and related files, and finally sends the resulting web page data back to the browser.\nBased on transport protocols such as HTTP and HTTPS, the web server\u0026rsquo;s data is transmitted back to the browser, which then parses and renders the web page.\nFinally, the user sees the web page.\n","date":"2015-10-15T15:24:04Z","permalink":"https://blog.coinidea.com/en/p/web-development-what-happens-after-a-user-enters-a-url/","title":"[Web Development] What Happens After a User Enters a URL?"},{"content":"DNS determines whether a server can reach the internet via domain names. There are two ways to configure DNS server IP addresses on Linux.\nVerification method:\n1 ping www.baidu.com Temporary method\na) Edit resolv.conf\n1 vi ./etc/resolv.conf b) Enter\n1 nameserver 8.8.8.8 Save and you\u0026rsquo;re done.\nPermanent method\na) Edit ifcfg-eth0\n1 vi /etc/sysconfig/network-scripts/ifcfg-eth0 b) Enter\n1 DNS1=8.8.8.8 Save and you\u0026rsquo;re done.\nYou can use\n1 ifconfig to view the local network interfaces, where you can see the eth0 configuration information.\n","date":"2015-10-14T13:28:18Z","permalink":"https://blog.coinidea.com/en/p/linux-configuring-dns-addresses-on-linux/","title":"[Linux] Configuring DNS Addresses on Linux"},{"content":"The server runs CentOS and needs to mount two 2TB external hard drives.\nThe command is as follows:\n1 2 mount -t ntfs /dev/sdn1 /test1 mount： unknown filesystem type \u0026#39;ntfs\u0026#39; An error occurred, meaning the system does not recognize \u0026ldquo;NTFS.\u0026rdquo; The solution is as follows:\n1 2 3 4 5 6 7 8 wget http://tuxera.com/opensource/ntfs-3g_ntfsprogs-2013.1.13.tgz tar zxvf ntfs-3g_ntfsprogs-2013.1.13.tgz cd ntfs-3g_ntfsprogs-2013.1.13 ./configure make make install mkdir /mnt/window mount -t ntfs-3g /dev/sdn1 /mnt/window To unmount:\n1 umount /dev/sdn1 ","date":"2015-10-01T06:26:08Z","permalink":"https://blog.coinidea.com/en/p/linux-mounting-an-ntfs-external-hard-drive-on-centos/","title":"[Linux] Mounting an NTFS External Hard Drive on CentOS"},{"content":"A distributed real-time computation system for processing high-speed, large-volume data streams. It adds reliable real-time data processing capabilities to Hadoop.\nHome link: http://storm.apache.org/\nDownload link: http://storm.apache.org/downloads.html\nSetup\nJava CentOS comes with JDK 1.7, so this step can be skipped.\nZookeeper Home link: http://zookeeper.apache.org/releases.html\nDownload the package, upload, and extract\nhttp://mirror.bit.edu.cn/apache/zookeeper/stable/\n1 tar -xf zookeeper-3.4.6.tar.gz Configure Zookeeper\n1 2 3 4 5 6 7 8 tickTime=2000 dataDir=/var/zookeeper/ clientPort=2181 initLimit=5 syncLimit=2 server.1=zookeeper1:2888:3888 server.2=zookeeper2:2888:3888 server.3=zookeeper3:2888:3888 Start Zookeeper\n1 bin/zkServer.sh start Test\n1 bin/zkCli.sh -server 127.0.0.1:2181 Dependency installation\nJava\nPre-installed.\nPython\nPre-installed.\nStorm\nDownload the package, upload, and extract\nExtract command:\n1 tar -xf apache-storm-0.9.5.tar.gz Configure the Zookeeper address in storm.yaml\n1 2 storm.zookeeper.servers: - \u0026#34;127.0.0.1\u0026#34; Create and configure the workdir\n1 storm.local.dir: \u0026#34;/home/admin/storm/workdir\u0026#34; Note: storm.local.dir is the local disk directory used by Nimbus and Supervisor processes to store a small amount of state (such as jars, confs, etc.). This directory must be created in advance with sufficient access permissions.\n1 nimbus.host: \u0026#34;127.0.0.1\u0026#34; 1 2 3 4 5 supervisor.slots.ports: - 6700 - 6701 - 6702 - 6703 Start all Storm services\nNimbus\n1 bin/storm nimbus \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp; Supervisor\n1 bin/storm supervisor \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp; UI\n1 bin/storm ui \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp; Logview\n1 bin/storm logviewer \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 Access Storm UI\nhttp://ip:8080\n","date":"2015-10-01T05:12:26Z","permalink":"https://blog.coinidea.com/en/p/storm-installing-storm/","title":"[Storm] Installing Storm"},{"content":"Once you enter the workplace, Outlook becomes an essential tool for office workers. This article explains some configuration and general settings for Outlook (Outlook 2013).\nAdding a User Account Open Outlook 2013, click \u0026ldquo;File\u0026rdquo; in the upper left corner, and in the dropdown list, click \u0026ldquo;+ Add Account.\u0026rdquo; Select \u0026ldquo;Email Account\u0026rdquo; and click \u0026ldquo;Next.\u0026rdquo; Click \u0026ldquo;Manual setup or additional server types,\u0026rdquo; then click \u0026ldquo;Next.\u0026rdquo; Check \u0026ldquo;POP or IMAP,\u0026rdquo; then click \u0026ldquo;Next.\u0026rdquo; This is generally the option to choose. Enter your username and password, and configure the incoming and outgoing server addresses. Note that these two addresses are typically pop3 or smtp@corresponding-domain, which you need to confirm with your email service provider. The provider usually has documentation for this. Click \u0026ldquo;More Settings\u0026rdquo; in the image above, configure the outgoing server username and password, and click \u0026ldquo;Finish.\u0026rdquo; Click Next to start the test. After the test completes, the entire process is successful. Configuring Email Filter Rules During daily email usage, you may receive a large volume of emails. Efficiently sorting these emails is a very meaningful task.\nOpen Outlook 2013, click \u0026ldquo;File\u0026rdquo; in the upper left corner, and in the dropdown list, click \u0026ldquo;Manage Rules \u0026amp; Alerts.\u0026rdquo; Click \u0026ldquo;New Rule.\u0026rdquo; There are many options in the rules. Configure them according to the rule wizard. For example, you can select \u0026ldquo;with specific words in the subject\u0026rdquo; or \u0026ldquo;from a specific sender,\u0026rdquo; and then move the emails to a designated folder or specify a particular action. ","date":"2015-10-01T03:13:11Z","permalink":"https://blog.coinidea.com/en/p/outlook-outlook-configuration-and-general-settings-outlook-2013/","title":"[Outlook] Outlook Configuration and General Settings — Outlook 2013"},{"content":"1. Connect server Use CRT or Xshell to connect to the server remotely.\n2. Network config First, configure DNS for the server and check whether it can access the internet. Enter the following command:\n1 ping [www.baidu.com][1] If you receive a reply from [www.baidu.com][1], it means the server can access the internet. If you get \u0026ldquo;unknown host,\u0026rdquo; the DNS configuration is incorrect and needs to be set up.\nThere are two ways to configure DNS:\nTemporary solution: edit the resolv.conf file and add \u0026ldquo;nameserver 8.8.8.8\u0026rdquo;.\n1 2 vi /etc/resolv.conf nameserver 8.8.8.8 Permanent solution: edit the ifcfg_eth0 file and add \u0026ldquo;DNS1=8.8.8.8\u0026rdquo;.\n1 2 vi /etc/sysconfig/network-scripts/ifcfg-eth0 DNS1=8.8.8.8 After configuration, run the command \u0026ldquo;service network restart\u0026rdquo;.\nThe second approach is recommended, as the first one will be lost when the server restarts.\nDisable the firewall\nEnter the command:\n1 service iptables stop 3. File transfer During the installation process, you may need to upload local files to the server. Here is one approach.\nEnter the command:\n1 sudo yum install lrzsz After installing the lrzsz package, enter:\n1 rz Then select the file you want to upload.\nYum (Yellow dog Updater Modified) is an RPM-based package manager that can automatically download and install RPM packages from specified servers, handling dependency relationships automatically and installing all dependent packages at once, eliminating the tedious process of downloading and installing them one by one.\n4. Install CDH HDFS: A distributed file storage system, the open-source Java implementation of GFS.\nMapReduce: A parallel computing programming model for large-scale datasets.\nHBase: NoSQL column database\nHive: Data warehouse\nZookeeper: Distributed lock service\nPig: Big data analysis platform interface\nHome link: http://www.cloudera.com/content/cloudera/en/products-and-services/cdh.html\nSetup:\n1. Java\nCentOS 6.7 comes with JDK 1.7, so this step can be skipped. Any JDK-related steps during installation can be ignored.\n2. Cloudera Manager Server\nCloudera Manager makes it easy to manage Hadoop deployments of any scale in production. Quickly deploy, configure, and monitor your cluster through an intuitive UI – complete with rolling upgrades, backup and disaster recovery, and customizable alerting.\nDownload:\nhttp://www.cloudera.com/content/cloudera/en/downloads/cloudera_manager/cm-5-4-7.html\nDownload the latest version 5.4.7.\nAfter downloading, you will get a file of about 503KB named cloudera-manager-installer.bin. Upload this file (using \u0026ldquo;rz\u0026rdquo;) to a designated folder on the server.\nClose selinux:\n1 2 /etc/selinux/config selinux=disabled Hostname\nYou need to modify the hostname of the machine. To check the current hostname, simply type hostname.\nEnter:\n1 vi /etc/hosts Edit the file and add the line \u0026ldquo;192.168._._ master.com master\u0026rdquo;.\nNote: when adding datanode nodes, do not name them \u0026ldquo;master\u0026rdquo; \u0026ndash; use names like \u0026ldquo;datanode1\u0026rdquo; instead.\nRun the \u0026ldquo;reboot\u0026rdquo; command to restart the server.\n3. CDH\nUsing cloudera manager\nNavigate to the directory containing cloudera-manager-installer.bin and run:\n1 2 chmod u+x cloudera-manager-installer.bin ./ cloudera-manager-installer.bin Keep clicking next. The selected items will be highlighted in bold.\nThis may take a while, so please be patient\u0026hellip;\nChoose express free version.\nDisplay the packages to be installed\nSpecify CDH cluster hosts\nInstall CDH\nEnter username and password\nInstall the specified Parcel\nSelect services\n4. Storm A distributed real-time computation system for processing high-speed, large-volume data streams. It adds reliable real-time data processing capabilities to Hadoop.\n5. Spark Spark uses in-memory computing. Starting from multi-iteration batch processing, it allows data to be loaded into memory for repeated queries. It also integrates multiple computing paradigms such as data warehousing, stream processing, and graph computing. Spark is built on top of HDFS and integrates well with Hadoop.\n6. Problems Refreshing metadata packages\n1 2 Another app is currently holding the yum lock; waiting for it to exit... rm -f /var/run/yum.pid Uninstall Cloudera Manager\n1 $ sudo /usr/share/cmf/uninstall-cloudera-manager.sh Installation failed: Unable to receive heartbeat from Agent\n1 2 3 4 5 cat /etc/hosts ip 域名 主机名 192.168.*.1 master.com master cat /etc/sysconfig/network HOSTNAME=master.com Uninstall Cloudera Manager\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sudo rm -Rf /usr/share/cmf /var/lib/cloudera* /var/cache/yum/cloudera* sudo /usr/share/cmf/uninstall-cloudera-manager.sh sudo service cloudera-scm-server stop sudo service cloudera-scm-server-db stop cloudera-manager-server-db sudo yum remove cloudera-manager-server sudo yum remove cloudera-manager-server-db-2 sudo service cloudera-scm-agent hard_stop sudo yum remove \u0026#39;cloudera-manager-*\u0026#39; sudo yum clean all sudo rm -Rf /usr/share/cmf /var/lib/cloudera* /var/cache/yum/cloudera* /var/log/cloudera* /var/run/cloudera* sudo rm -Rf /var/cache/apt/archives/cloudera* sudo rm /tmp/.scm_prepare_node.lock sudo rm -Rf /var/lib/flume-ng /var/lib/hadoop* /var/lib/hue /var/lib/navigator /var/lib/oozie /var/lib/solr /var/lib/sqoop* /var/lib/zookeeper sudo rm -Rf /dfs /mapred /yarn ","date":"2015-09-28T14:50:42Z","permalink":"https://blog.coinidea.com/en/p/hadoop-setting-up-the-cdh-environment/","title":"[Hadoop] Setting Up the CDH Environment"},{"content":"Because I open-sourced a WIN32 Snake game, I wanted to create a GIF for demonstration purposes, but figuring out how to actually make one turned out to be tricky.\nAfter some research, here are several methods:\nMethod 1: Using video software like QQ Player The prerequisite is that you have a short video clip to convert. You can use QQ Player\u0026rsquo;s built-in feature to do the conversion.\nDetailed instructions:\nhttp://kf.qq.com/faq/120322fu63YV130422iiEbMB.html\nMethod 2: Using professional software like Photoshop Prepare multiple frames of images. See this Baidu tutorial for detailed instructions:\nhttp://jingyan.baidu.com/article/7f41ececdb326e593d095c2e.html\nMethod 3: Using Screen Recording Expert The image above was created using Screen Recording Expert. First, I recorded a video (in EXE or LXE format), then selected the \u0026ldquo;Conversion Tools\u0026rdquo; menu, and converted it from there.\nHere is a download link for a portable version of Screen Recording Expert:\nScreen Recording Expert.\n","date":"2015-09-20T08:37:13Z","permalink":"https://blog.coinidea.com/en/p/software-creating-gif-images-locally/","title":"[Software] Creating GIF Images Locally"},{"content":"I recently rushed through reading \u0026ldquo;Zero to One.\u0026rdquo; After finishing a book, I always want to write something, but when I actually sit down at the keyboard, I never quite know where to begin. In the past, when writing summaries or book notes, I would pull out the original book and type up the passages I found interesting, but I feel that approach lacks real substance when you chew on it.\nThis book has a rating of 8.0 on Douban and is quite a slim volume. Given my limited life experience, I wouldn\u0026rsquo;t dare to rate this book myself, but I feel that reading it once is certainly not enough.\nAt first glance, this book seems a bit like motivational writing, yet also a bit like anti-motivational writing. It talks about big principles, but big principles are not necessarily the ones people remember to apply in practice.\nThe most important impressions this book left on me can be summed up in a few words.\nThe First: Qualitative Change In common terms, quantitative changes lead to qualitative changes, but this book approaches it from the perspective of innovation: taking that first step is what is truly great \u0026ndash; like the first person to eat a crab. Everything that follows is just replication, a less meaningful accumulation.\nThe Second: Monopoly Whether in personal life, career, or running a company, the most important thing is to have a unique skill. I remember my advisor once said, \u0026ldquo;One signature skill can feed you anywhere.\u0026rdquo; That is essentially the idea. For those in technology, technical ability is king. In recent years (2015), with the wave of mass entrepreneurship, people pitch to investors telling stories like \u0026ldquo;I have a great idea,\u0026rdquo; and so on. But the ones that truly survive \u0026ndash; whether companies or employees within companies \u0026ndash; are those with a distinctive skill. I wouldn\u0026rsquo;t say they are completely irreplaceable; I have always believed nothing is truly irreplaceable. But when someone creates great value on one hand, and the cost of replacing them is very high on the other, nobody is willing to replace them. That is when a kind of monopoly forms, and this is also the significance of patents. Take WeChat, for example. Current chat apps like Laiwang, Momo, and even a swarm of startups using similar concepts \u0026ndash; campus-based, dating-based, entrepreneurship-based, family-based, and so on \u0026ndash; are their technical capabilities not strong enough? Are their resources not abundant enough? Are their ideas not fresh enough? Yet WeChat remains irreplaceable, at least for now. This is a form of \u0026ldquo;monopoly.\u0026rdquo;\nThe Third: Secrets When a person or a company can uncover a secret that triggers qualitative change and creates monopoly, that company has succeeded. This sounds quite mystical, but it makes a lot of sense. As for how exactly to put it into practice? My experience is still limited, and I hope that the next time I read this book, I will have a deeper understanding.\nThe above are my thoughts after reading this book.\n","date":"2015-09-20T08:22:12Z","permalink":"https://blog.coinidea.com/en/p/book-notes-zero-to-one/","title":"[Book Notes] Zero to One"},{"content":"\n","date":"2015-09-18T16:11:12Z","permalink":"https://blog.coinidea.com/en/p/android-weekly-study-report-5-the-global-loudspeaker-a-detailed-look-at-the-broadcast-mechanism/","title":"[Android] Weekly Study Report 5: The Global Loudspeaker — A Detailed Look at the Broadcast Mechanism"},{"content":"Because the houses form a circle, we iterate over each point as the starting point, exclude its adjacent points, and assume the starting point is always selected. Then we can reuse the solution from House Robber.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class Solution { public: int robOne(vector\u0026amp; nums) { if (nums.size() == 0) { return 0; } vector v(nums.size() + 1); v[0] = 0; v[1] = nums[0]; for (int i = 1; i \u0026lt; nums.size(); i++) { int j = i + 1; if (nums[i] + v[j - 2] \u0026gt; v[j - 1]) { v[j] = nums[i] + v[j - 2]; } else { v[j] = v[j - 1]; } } return v[nums.size()]; } int rob(vector\u0026amp; nums) { vector numsc; int size = nums.size(); int sum = 0; for (int i = 0; i \u0026lt; size; i++) { numsc.clear(); int tmp = nums[i]; for (int j = i; j \u0026lt; size; j++) { if (j == ((i-1) \u0026lt; 0 ? i - 1 + size : i - 1) || j == ((i+1) \u0026gt;= size ? i + 1 - size : i + 1) || j == i) { numsc.push_back(0); continue; } numsc.push_back(nums[j]); } for (int j = 0; j \u0026lt; i; j++) { if (j == ((i-1) \u0026lt; 0 ? i - 1 + size : i - 1) || j == ((i+1) \u0026gt;= size ? i + 1 - size : i + 1) || j == i) { numsc.push_back(0); continue; } numsc.push_back(nums[j]); } tmp += robOne(numsc); if (tmp \u0026gt;= sum) { sum = tmp; } } return sum; } }; ","date":"2015-09-18T14:45:21Z","permalink":"https://blog.coinidea.com/en/p/leetcode_213house-robber-ii/","title":"[leetcode_213]House Robber II"},{"content":"\n","date":"2015-09-16T14:29:56Z","permalink":"https://blog.coinidea.com/en/p/android-weekly-study-report-4-supporting-both-phones-and-tablets-exploring-fragments/","title":"[Android] Weekly Study Report 4: Supporting Both Phones and Tablets — Exploring Fragments"},{"content":"\n","date":"2015-09-14T12:30:45Z","permalink":"https://blog.coinidea.com/en/p/android-weekly-study-report-3-looks-matter-for-apps-too-the-bits-and-pieces-of-ui-development/","title":"[Android] Weekly Study Report 3: Looks Matter for Apps Too — The Bits and Pieces of UI Development"},{"content":"Finding the k-th largest number. I took a shortcut and just used a direct sort. The proper approach should be simulating quickselect.\n1 2 3 4 5 6 7 class Solution { public: int findKthLargest(vector\u0026lt;int\u0026gt;\u0026amp; nums, int k) { sort(nums.begin(), nums.end(), greater\u0026lt;int\u0026gt;()); return nums[k - 1]; } }; ","date":"2015-09-14T12:29:31Z","permalink":"https://blog.coinidea.com/en/p/leetcode_215-kth-largest-element-in-an-array/","title":"[leetcode_215] Kth Largest Element in an Array"},{"content":"This solution passes, but it does not use an O(log n) approach. Marking this for a revisit next time.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public: int hIndex(vector\u0026lt;int\u0026gt;\u0026amp; citations) { //sort(citations.begin(), citations.end(), greater\u0026lt;int\u0026gt;()); int size = citations.size(); int max = 0; for (int i = size - 1; i \u0026gt;= 0; i--) { int j = size - 1 - i; if (citations[i] \u0026gt;= j + 1) { max = j + 1; } } return max; } }; ","date":"2015-09-14T12:28:35Z","permalink":"https://blog.coinidea.com/en/p/leetcode_275h-index-ii/","title":"[leetcode_275]H-Index II"},{"content":"Sort in descending order, then perform a linear search to find the qualifying h-index.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public: int hIndex(vector\u0026lt;int\u0026gt;\u0026amp; citations) { sort(citations.begin(), citations.end(), greater\u0026lt;int\u0026gt;()); int size = citations.size(); int max = 0; for (int i = 0; i \u0026lt; size; i++) { if (citations[i] \u0026gt;= i + 1) { max = i + 1; } } return max; } }; ","date":"2015-09-14T12:27:38Z","permalink":"https://blog.coinidea.com/en/p/leetcode_274h-index/","title":"[leetcode_274]H-Index"},{"content":"Continuing from [Android] Weekly Study Report 1: Getting Started \u0026ndash; Your First Line of Android Code.\nActivities are the most intuitive and first-encountered of the four major components. Today I ran a 5km mini marathon, so I\u0026rsquo;m taking a break before diving deeper into Android.\n","date":"2015-09-13T08:33:48Z","permalink":"https://blog.coinidea.com/en/p/android-weekly-study-report-2-start-with-what-you-can-see--exploring-activities/","title":"[Android] Weekly Study Report 2: Start with What You Can See -- Exploring Activities"},{"content":"Similar approach to Find Minimum in Rotated Sorted Array.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public: int min; void search(int left, int right, vector\u0026lt;int\u0026gt;\u0026amp; nums) { if (right \u0026lt; left) { return; } int mid = (left + right) / 2; if (nums[mid] \u0026lt; min) { min = nums[mid]; search(left, mid - 1, nums); search(mid + 1, right, nums); } else if (nums[mid] \u0026gt;= min) { search(left, mid - 1, nums); search(mid + 1, right, nums); } } int findMin(vector\u0026lt;int\u0026gt;\u0026amp; nums) { min = nums[0]; search(0, nums.size() - 1, nums); return min; } }; ","date":"2015-09-13T08:22:43Z","permalink":"https://blog.coinidea.com/en/p/leetcode-154-find-minimum-in-rotated-sorted-array-ii/","title":"[LeetCode 154] Find Minimum in Rotated Sorted Array II"},{"content":"Depth-first search.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; result; vector\u0026lt;int\u0026gt; list; void search(int now, int k, int n, int sum) { if (list.size() == k \u0026amp;\u0026amp; sum == n) { result.push_back(list); } if (list.size() \u0026gt;= k || now \u0026gt; 9) { return; } list.push_back(now); search(now + 1, k , n , sum + now); list.pop_back(); search(now + 1, k , n , sum); } vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; combinationSum3(int k, int n) { result.clear(); list.clear(); search(1, k, n, 0); return result; } }; ","date":"2015-09-13T08:20:50Z","permalink":"https://blog.coinidea.com/en/p/leetcode_216combination-sum-iii/","title":"[leetcode_216]Combination Sum III"},{"content":"Due to the special properties of the matrix, we can simply start searching from the top-left corner.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public: bool searchMatrix(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp; matrix, int target) { int row = matrix.size() - 1; int cols = matrix[0].size() - 1; int x = 0; int y = cols; while (x \u0026lt;= row \u0026amp;\u0026amp; y \u0026gt;= 0) { if (target == matrix[x][y]) { return true; } else if (target \u0026gt; matrix[x][y]) { x++; } else { y--; } } return false; } }; ","date":"2015-09-13T08:20:04Z","permalink":"https://blog.coinidea.com/en/p/leetcode_240search-a-2d-matrix-ii/","title":"[leetcode_240]Search a 2D Matrix II"},{"content":"I have been learning Android for about a month now. I want to systematically summarize my learning progress at each stage. Currently I am using the book \u0026ldquo;The First Line of Code: Android\u0026rdquo; as an introductory guide. This week I did a brief review of Chapter 1. Below is a simple mind map I created. Feel free to double-click to view the full-size image and save it.\n","date":"2015-09-10T15:11:55Z","permalink":"https://blog.coinidea.com/en/p/android-weekly-study-report-1-getting-started--your-first-line-of-android-code/","title":"[Android] Weekly Study Report 1: Getting Started -- Your First Line of Android Code"},{"content":"Website SEO is very important, and search engine optimization is a key part of it. The first step is to get your website indexed by search engines. Below are the submission URLs for major search engines:\nBaidu Website Submission: http://zhanzhang.baidu.com/linksubmit/url\nGoogle Website Submission: https://www.google.com/webmasters/tools/submit-url\n360 Search Submission: http://info.so.360.cn/site_submit.html\nSoso Website Submission: http://www.soso.com/help/usb/urlsubmit.shtml\nSogou Website Submission: http://www.sogou.com/feedback/urlfeedback.php\nBing Website Submission: http://www.bing.com/toolbox/submit-site-url\n","date":"2015-09-10T15:01:40Z","permalink":"https://blog.coinidea.com/en/p/seo-search-engine-submission-urls/","title":"[SEO] Search Engine Submission URLs"},{"content":"Find the k-th smallest element in a binary search tree. Perform an in-order traversal to generate the sorted sequence, store it in an array, and return the k-th element.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public: vector\u0026lt;int\u0026gt; list; void queryTree(TreeNode * node) { if (NULL == node) { return; } if (NULL != node-\u0026gt;left) { queryTree(node-\u0026gt;left); } list.push_back(node-\u0026gt;val); if (NULL != node-\u0026gt;right) { queryTree(node-\u0026gt;right); } } int kthSmallest(TreeNode* root, int k) { list.clear(); queryTree(root); return list[k-1]; } }; ","date":"2015-09-10T14:34:22Z","permalink":"https://blog.coinidea.com/en/p/leetcode-230-kth-smallest-element-in-a-bst/","title":"[LeetCode 230] Kth Smallest Element in a BST"},{"content":"Determine whether there exist two identical elements in an array whose index difference is at most k. A hash map problem.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public: bool containsNearbyDuplicate(vector\u0026lt;int\u0026gt;\u0026amp; nums, int k) { map\u0026lt;int, int\u0026gt; mNums; mNums.clear(); for (int i = 0;i \u0026lt; nums.size();i++) { map\u0026lt;int,int\u0026gt;::iterator it = mNums.find(nums[i]); if (mNums.end() == it) { mNums.insert(pair\u0026lt;int,int\u0026gt;(nums[i], i)); } else { if (i - it-\u0026gt;second \u0026lt;= k) { return true; } mNums.erase(it); mNums.insert(pair\u0026lt;int,int\u0026gt;(nums[i], i)); } } return false; } }; ","date":"2015-09-09T12:36:36Z","permalink":"https://blog.coinidea.com/en/p/leetcode-219-contains-duplicate-ii/","title":"[LeetCode 219] Contains Duplicate II"},{"content":"Calculate the total area of two rectangles, which may have an overlapping region.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public: int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) { int bx,by,tx,ty; bx = A \u0026gt; E ? A : E; by = B \u0026gt; F ? B : F; tx = C \u0026lt; G ? C : G; ty = D \u0026lt; H ? D : H; int same = 0; if (tx \u0026lt;= bx || ty \u0026lt;= by) { same = 0; } else { same = (tx - bx) * (ty - by); } return (C - A) * (D - B) + (G - E) * (H - F) - same; } }; ","date":"2015-09-09T12:35:06Z","permalink":"https://blog.coinidea.com/en/p/leetcode-223-rectangle-area/","title":"[LeetCode 223] Rectangle Area"},{"content":"Select numbers from an array of positive integers to maximize the sum, with the constraint that no two adjacent numbers can be selected.\nOne could enumerate all 2^n cases, but that\u0026rsquo;s too expensive. Instead, use one-dimensional dynamic programming: f(n) = max(f(n-1), nums[n] + f(n-2));\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public: int rob(vector\u0026lt;int\u0026gt;\u0026amp; nums) { if (nums.size() \u0026lt;= 0) { return 0; } vector\u0026lt;int\u0026gt; v(nums.size() + 1); v[0] = 0; v[1] = nums[0]; for (int i = 1; i \u0026lt; nums.size(); i++) { int j = i + 1; if (nums[i] + v[j - 2] \u0026gt; v[j - 1]) { v[j] = nums[i] + v[j-2]; } else { v[j] = v[j-1]; } } return v[nums.size()]; } }; ","date":"2015-09-07T15:19:40Z","permalink":"https://blog.coinidea.com/en/p/leetcode-198-house-robber/","title":"[LeetCode 198] House Robber"},{"content":"Find the rightmost node value at each level of a binary tree. Serialize each level and output the last node of each level.\nclass Solution { public: vector\u0026lt;int\u0026gt; rightSideView(TreeNode* root) { vector\u0026lt;int\u0026gt; ans(0); if (NULL == root) { return ans; } queue\u0026lt;TreeNode *\u0026gt; qList; qList.push(root); while (qList.size() \u0026gt; 0) { int size = qList.size(); for (int i = 0;i \u0026lt; size;i++) { TreeNode * head = qList.front(); if (NULL != head-\u0026gt;left) { qList.push(head-\u0026gt;left); } if (NULL != head-\u0026gt;right) { qList.push(head-\u0026gt;right); } qList.pop(); if (i == size-1) { ans.push_back(head-\u0026gt;val); } } } return ans; } }; ","date":"2015-09-07T04:58:23Z","permalink":"https://blog.coinidea.com/en/p/leetcode-199-binary-tree-right-side-view/","title":"[LeetCode 199] Binary Tree Right Side View"},{"content":"Given an array where all numbers appear in pairs except for two numbers, find those two numbers.\nThe single-number case is well known \u0026ndash; just XOR everything. With two unique numbers, XOR gives a^b. Since a^b is non-zero, pick any bit position where it is 1, partition the array into two groups based on that bit, and XOR each group separately to get a and b.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public: vector\u0026lt;int\u0026gt; singleNumber(vector\u0026lt;int\u0026gt;\u0026amp; nums) { int ab = 0; for (int i = 0; i \u0026lt; nums.size(); i++) { ab ^= nums[i]; } int pos = 0; while(0 == ab % 2) { pos++; ab /= 2; } int a = 0; int b = 0; int tmp = (int)pow(2.0, pos); for (int i = 0; i \u0026lt; nums.size(); i++) { if ((nums[i]^tmp) == (nums[i] - tmp)) { a ^= nums[i]; } else { b ^= nums[i]; } } vector\u0026lt;int\u0026gt; ans(0); ans.push_back(a); ans.push_back(b); return ans; } }; ","date":"2015-09-07T04:57:15Z","permalink":"https://blog.coinidea.com/en/p/leetcode-260-single-number-iii/","title":"[LeetCode 260] Single Number III"},{"content":"GitHub download link: https://github.com/hujiulin/TypingGame\nDouble-click to run the program. The main interface will appear:\nClick the \u0026ldquo;User\u0026rdquo; menu to perform Login and Register operations. If you have not registered, you can register first and then log in. Here we use UserName as an example.\nClick Login to open the login window:\nClick Register to open the registration window (or click the Register button directly):\nEnter Username: UserName; Nickname: UserName; Password: UserName; as shown below:\nClick OK to complete registration.\nLog in with the UserName account, and you will see the following information in the upper-right corner of the main interface:\nConfigure game settings: . In the game options, you can set \u0026ldquo;Game Difficulty\u0026rdquo;, \u0026ldquo;Image Category\u0026rdquo;, and \u0026ldquo;Background Music\u0026rdquo;.\nGame Difficulty:\nClick the Game Difficulty button to open the following dialog:\nYou can use the dropdown lists to configure \u0026ldquo;Vocabulary Size\u0026rdquo;, \u0026ldquo;Spelling Difficulty\u0026rdquo;, \u0026ldquo;Word Frequency\u0026rdquo;, and \u0026ldquo;Movement Speed\u0026rdquo;. Vocabulary size options are 50, 100, and 150. Spelling difficulty currently uses random CET-4 words. Word frequency can be single or double. Movement speed can be fast, medium, or slow. Click Set to apply.\nImage Category:\nClick the Image Category button to open the following dialog:\nCurrently available images include balloons and fish. Select a radio button to choose.\nBackground Music:\nClick the Background Music button to open the following dialog:\nSelect the desired music in the group box and click \u0026ldquo;Select Music\u0026rdquo;.\nThe configured game options will be displayed at: .\nClick to open the following window:\nThis shows the top five highest-scoring users in the system.\n, the Help menu has two sections: Game Rules and About.\nGame Rules:\nAbout:\nThis area shows the current game state: Started or Stopped.\nClick these two buttons to start or exit the game.\nBelow is a screenshot taken during gameplay:\n","date":"2015-09-03T15:18:16Z","permalink":"https://blog.coinidea.com/en/p/mfc-implementation-of-the-wordgame-typing-game/","title":"MFC Implementation of the WordGame Typing Game"},{"content":"This is a simple snake game available in both WIN32 and JavaScript versions. The WIN32 version was written in 2010 \u0026ndash; small but complete. Looking back, I\u0026rsquo;m quite impressed with myself from over five years ago. The jQuery version was written in 2015.\nGitHub download link: https://github.com/hujiulin/snake\njQuery demo: http://www.coinidea.com/game/snake/\nThe overall interface looks like this:\nWIN32 Version: jQuery Version: WIN32 Framework Code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include \u0026lt;windows.h\u0026gt; #include \u0026lt;math.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;time.h\u0026gt; #include \u0026lt;string.h\u0026gt; LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { WNDCLASS wndclass; char strClassName[] = \u0026#34;hungry snake\u0026#34;; char strWindowName[] = \u0026#34;贪吃蛇\u0026#34;; HWND hwnd; MSG msg; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor = LoadCursor(hInstance,IDC_ARROW); wndclass.hIcon = LoadIcon(hInstance,IDI_APPLICATION); wndclass.hInstance = hInstance; wndclass.lpfnWndProc = WndProc; wndclass.lpszClassName = strClassName; wndclass.lpszMenuName = NULL; wndclass.style = 0; if(!RegisterClass(\u0026amp;wndclass)) { MessageBeep(0); return FALSE; } hwnd = CreateWindow( strClassName, strWindowName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); while(GetMessage(\u0026amp;msg,NULL,0,0)) { TranslateMessage(\u0026amp;msg); DispatchMessage(\u0026amp;msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; HBRUSH hBrush; HPEN hPen; switch(msg) { case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_CHAR: case WM_PAINT: InvalidateRect(hwnd,NULL,1); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,msg,wParam,lParam); } return 0; } Snake Definition The entire snake is a List, with a head squarehead, a direction with four possible values, a speed, and the current snake length List.size().\nCollision Detection When the snake\u0026rsquo;s head encounters a randomly generated square in the current direction, it means food has been eaten. When the snake turns back and hits its own body, or hits the boundary, the game is over. ","date":"2015-09-03T15:13:45Z","permalink":"https://blog.coinidea.com/en/p/open-source-snake-game-in-win32-and-jquery/","title":"Open-Source Snake Game in WIN32 and jQuery"},{"content":"Sample components built on open-source data visualization libraries (MSChart, VTK, D3), with a World Wind plugin that invokes these components.\nGitHub download link: https://github.com/hujiulin/WorldWind_DataVisualization\n1. Load Plugin 2. DataVisualization2D Component 3. DataVisualization3D Component 4. DataVisualizationWEB Component Original link: http://cesiumcn.org/topic/207.html | China mirror: http://cesium.coinidea.com/topic/207.html\n","date":"2015-09-03T15:11:46Z","permalink":"https://blog.coinidea.com/en/p/data-visualization-plugin-based-on-world-wind/","title":"Data Visualization Plugin Based on World Wind"},{"content":"Reverse a singly linked list.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public: ListNode* reverseList(ListNode* head) { if (NULL == head) { return head; } ListNode * before = NULL; ListNode * now = head; ListNode * next = now-\u0026gt;next; while (NULL != next) { ListNode * beforeTmp = now; ListNode * nowTmp = next; ListNode * nextTmp = next-\u0026gt;next; now-\u0026gt;next = before; next-\u0026gt;next = now; before = beforeTmp; now = nowTmp; next = nextTmp; } head = now; return head; } }; ","date":"2015-09-01T14:53:34Z","permalink":"https://blog.coinidea.com/en/p/leetcode-206-reverse-linked-list/","title":"[LeetCode 206] Reverse Linked List"},{"content":"In Android development, you may need custom layouts. For example, apps often require a common title bar. However, the built-in options may not meet your needs, so you have to implement one yourself. Since an app typically contains multiple Activities, it is common practice to define a CommonTitle for better reusability. This article demonstrates a custom CommonTitle implementation.\nCreate a new layout\n1 2 3 \u0026lt;!--?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?--\u0026gt; \u0026lt;button\u0026gt; \u0026lt;/button\u0026gt; Create a new CommonTitle class extending LinearLayout\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.example.uicustomviews; import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; public class CommonTitle extends LinearLayout { public CommonTitle(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.commontitle, this); Button backButton = (Button)findViewById(R.id.backButton); backButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // TODO Auto-generated method stub ((Activity)getContext()).finish(); } }); Button editButton = (Button)findViewById(R.id.editButton); editButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // TODO Auto-generated method stub Toast.makeText(getContext(), \u0026#34;Please edit the context\u0026#34;, Toast.LENGTH_SHORT).show(); } }); } } Include your custom CommonTitle in the Activity that needs it\n1 \u0026lt;!-- Your Activity layout XML --\u0026gt; The result looks like this:\n","date":"2015-08-31T14:09:07Z","permalink":"https://blog.coinidea.com/en/p/android-common-controls-and-event-handling/","title":"Android Common Controls and Event Handling"},{"content":"Given an input array a1, a2, a3, \u0026hellip;\nGenerate an output array where each element is the product of all other elements, e.g. a2a3, a1a3, a1*a2. The goal is to solve it in O(n) time without using division.\nUse two extra arrays to store the prefix product and suffix product for each index.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public: vector\u0026lt;int\u0026gt; productExceptSelf(vector\u0026lt;int\u0026gt;\u0026amp; nums) { int size = nums.size(); vector\u0026lt;int\u0026gt; front(size), back(size), result(size); front[0] = 1; back[size-1] = 1; for (int i = 1;i \u0026lt; size;i++) { front[i] = front[i-1] * nums[i-1]; } for (int i = size - 2;i \u0026gt;= 0;i--) { back[i] = back[i + 1] * nums[i + 1]; } result[0] = back[0]; result[size-1] = front[size - 1]; for (int i = 1;i \u0026lt; size - 1;i++) { result[i] = front[i] * back[i]; } return result; } }; ","date":"2015-08-31T11:47:19Z","permalink":"https://blog.coinidea.com/en/p/leetcode-238-product-of-array-except-self/","title":"[LeetCode 238] Product of Array Except Self"},{"content":"Count how many trailing zeroes n! has. The problem essentially reduces to counting the number of factor 5 in the prime factorization (since there are always more 2s than 5s). A naive approach of checking every number modulo 5 would time out; instead, you only need to compute the relationship between powers of 5 and n.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { public: int trailingZeroes(int n) { vector\u0026lt;int\u0026gt; five(14); for (int i = 1; i \u0026lt;= 13; i++) { five[i] = ((int)pow(5.0, i)); } int before = 0; int count = 0; for (int i = 13; i \u0026gt;= 1; i--) { if (five[i] \u0026lt;= n) { count += (n / five[i] - before) * i; before = (n / five[i]); } } return count; } }; ","date":"2015-08-31T11:43:47Z","permalink":"https://blog.coinidea.com/en/p/leetcode-172-factorial-trailing-zeroes/","title":"[LeetCode 172] Factorial Trailing Zeroes"},{"content":"Enumerate all paths of a binary tree \u0026ndash; a simple search will do.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Solution { public: string convertIntToStr(int num) { char str[255]; sprintf(str, \u0026#34;%d\u0026#34;, num); return str; } void binaryTreePath(TreeNode* node, string\u0026amp; path, vector\u0026lt;string\u0026gt;\u0026amp; paths) { if (NULL == node) { return; } path += convertIntToStr(node-\u0026gt;val); if (NULL != node-\u0026gt;left) { string tmp = path; path += \u0026#34;-\u0026gt;\u0026#34;; binaryTreePath(node-\u0026gt;left, path, paths); path = tmp; } if (NULL != node-\u0026gt;right) { string tmp = path; path += \u0026#34;-\u0026gt;\u0026#34;; binaryTreePath(node-\u0026gt;right, path, paths); path = tmp; } if (NULL == node-\u0026gt;left \u0026amp;\u0026amp; NULL == node-\u0026gt;right) { paths.push_back(path); } } vector\u0026lt;string\u0026gt; binaryTreePaths(TreeNode* root) { vector\u0026lt;string\u0026gt; paths; paths.clear(); string path = \u0026#34;\u0026#34;; binaryTreePath(root, path, paths); return paths; } }; ","date":"2015-08-28T14:24:23Z","permalink":"https://blog.coinidea.com/en/p/leetcode-257-binary-tree-paths/","title":"[LeetCode 257] Binary Tree Paths"},{"content":"Another way to describe the problem: Split the two input numbers by ., then compare them segment by segment. If the number of segments differs, the one with more segments is larger \u0026ndash; provided the extra segments contain a non-zero value.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class Solution { public: void getNums(string version1, vector\u0026lt;int\u0026gt; \u0026amp;v1) { int s = 0; int pos = version1.find(\u0026#34;.\u0026#34;); while (-1 != pos) { v1.push_back(atoi(version1.substr(s, pos - s).c_str())); s = pos + 1; pos = version1.find(\u0026#34;.\u0026#34;, pos + 1); } v1.push_back(atoi(version1.substr(s).c_str())); } int compareVersion(string version1, string version2) { vector\u0026lt;int\u0026gt; v1, v2; v1.clear(); v2.clear(); getNums(version1, v1); getNums(version2, v2); int min = v1.size() \u0026gt; v2.size() ? v2.size() : v1.size(); for (int i = 0; i \u0026lt; min;i++) { if (v1[i] \u0026gt; v2[i]) { return 1; } if (v1[i] \u0026lt; v2[i]) { return -1; } } if (v1.size() \u0026gt; v2.size()) { for (int i = min; i \u0026lt; v1.size(); i++) { if (v1[i] \u0026gt; 0) { return 1; } } return 0; } if (v1.size() \u0026lt; v2.size()) { for (int i = min; i \u0026lt; v2.size(); i++) { if (v2[i] \u0026gt; 0) { return -1; } } return 0; } return 0; } }; ","date":"2015-08-27T13:37:59Z","permalink":"https://blog.coinidea.com/en/p/leetcode_165-compare-version-numbers/","title":"[leetcode_165] Compare Version Numbers"},{"content":"Remove all nodes with a specified value from a singly linked list.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public: ListNode* removeElements(ListNode* head, int val) { if (NULL == head) { return NULL; } ListNode * before = NULL; ListNode * now = head; while (now != NULL) { if (now -\u0026gt; val == val) { if (before == NULL) { head = head-\u0026gt;next; now = head; } else { if (now != NULL) { before-\u0026gt;next = now-\u0026gt;next; } now = before-\u0026gt;next; } } else { before = now; now = now-\u0026gt;next; } } return head; } }; ","date":"2015-08-27T13:32:41Z","permalink":"https://blog.coinidea.com/en/p/leetcode_203remove-linked-list-elements/","title":"[leetcode_203]Remove Linked List Elements"},{"content":"Given a sequence from 0 to n with one number i missing, find i.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public: int missingNumber(vector\u0026lt;int\u0026gt;\u0026amp; nums) { int sum = 0; int max = 0; bool isZero = false; for (int i = 0; i \u0026lt; nums.size(); i++) { sum += nums[i]; if (nums[i] \u0026gt;= max) { max = nums[i]; } if (nums[i] == 0) { isZero = true; } } int oSum = (0 + max) * (max - 0 + 1) / 2; if (oSum == sum) { if (!isZero) { return 0; } else { return max + 1; } } else { return oSum - sum; } } }; ","date":"2015-08-27T13:30:51Z","permalink":"https://blog.coinidea.com/en/p/leetcode-268-missing-number/","title":"[LeetCode 268] Missing Number"},{"content":"Find the intersection node of two singly linked lists. The idea is simple: the longer list advances by the difference in length first.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { int countA = 0; int countB = 0; ListNode * tmpA = headA; ListNode * tmpB = headB; while(NULL != tmpA) { countA++; tmpA = tmpA-\u0026gt;next; } while(NULL != tmpB) { countB++; tmpB = tmpB-\u0026gt;next; } int move = 0; if (countA \u0026gt; countB) { while (move \u0026lt; countA - countB) { headA = headA-\u0026gt;next; move++; } } else { while (move \u0026lt; countB - countA) { headB = headB-\u0026gt;next; move++; } } while (headA != headB) { headA = headA-\u0026gt;next; headB = headB-\u0026gt;next; } return headA; } }; ","date":"2015-08-27T13:28:46Z","permalink":"https://blog.coinidea.com/en/p/leetcode_160intersection-of-two-linked-lists/","title":"[leetcode_160]Intersection of Two Linked Lists"},{"content":"Traversing a binary search tree is essentially an in-order traversal of the tree. An iterative approach can be used.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class BSTIterator { public: int pos; vector\u0026lt;TreeNode *\u0026gt; treeNodeStack; void buildStack(TreeNode *node) { if (node == NULL) { return; } else { if (NULL != node-\u0026gt;left) { buildStack(node-\u0026gt;left); } treeNodeStack.push_back(node); if (NULL != node-\u0026gt;right) { buildStack(node-\u0026gt;right); } } } BSTIterator(TreeNode *root) { pos = 0; treeNodeStack.clear(); buildStack(root); } /** @return whether we have a next smallest number */ bool hasNext() { return treeNodeStack.size() \u0026gt; pos; } /** @return the next smallest number */ int next() { return treeNodeStack[pos++]-\u0026gt;val; } }; ","date":"2015-08-27T13:27:01Z","permalink":"https://blog.coinidea.com/en/p/leetcode_173binary-search-tree-iterator/","title":"[leetcode_173]Binary Search Tree Iterator"},{"content":"Count the number of primes less than a given number n. The Sieve of Eratosthenes works well here.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public: int * flag; int countPrimes(int n) { flag = new int[n + 10]; for (int i = 1;i \u0026lt; n;i++) { flag[i] = 0; } for (int i = 2;i \u0026lt; n;i++) { if (0 == flag[i]) { flag[i] = 1; for (int j = 2;j * i \u0026lt; n; j++) { flag[j * i] = -1; } } } int count = 0; for (int i = 1;i \u0026lt; n; i++) { if (1 == flag[i]) { count++; } } return count; } }; ","date":"2015-08-27T13:25:23Z","permalink":"https://blog.coinidea.com/en/p/leetcode_204count-primes/","title":"[leetcode_204]Count Primes"},{"content":"Rotate an array based on input k. Note that k can be negative or greater than the array length, so take the modulus first. Then output the doubled array starting at offset size-k.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public: void rotate(vector\u0026lt;int\u0026gt;\u0026amp; nums, int k) { if (nums.size() \u0026lt;= 0) { return ; } k %= nums.size(); vector\u0026lt;int\u0026gt; dNums(nums.size() * 2); for (int i = 0;i \u0026lt; nums.size() * 2; i++) { dNums[i] = nums[i % nums.size()]; } for (int i = 0;i \u0026lt; nums.size(); i++) { nums[i] = dNums[i + nums.size() - k]; } } }; ","date":"2015-08-27T13:24:07Z","permalink":"https://blog.coinidea.com/en/p/leetcode_189rotate-array/","title":"[leetcode_189]Rotate Array"},{"content":"Convert a number to an Excel column title. At first I thought it was a simple base-26 conversion, but you need to consider that there is no 0 in this numeral system. So I temporarily used @ to represent 0, which requires an additional conversion step afterward.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Solution { public: string convertToTitle(int n) { string title = \u0026#34;\u0026#34;; while (n \u0026gt; 0) { title += \u0026#39;A\u0026#39; + n % 26 - 1; n /= 26; } int pos0 = 0; while (pos0 \u0026lt; title.length()) { int pos = pos0; while (title[pos] == \u0026#39;@\u0026#39; \u0026amp;\u0026amp; pos \u0026lt; title.length()) { title[pos] = \u0026#39;Z\u0026#39;; if (pos + 1 \u0026lt; title.length() \u0026amp;\u0026amp; title[pos + 1] != \u0026#39;@\u0026#39;) { title[pos+1]--; pos++; } else { title = title.substr(0, pos); break; } } pos0++; } int s = 0; int e = title.length() - 1; while (s \u0026lt; e) { char tmp = title[s]; title[s] = title[e]; title[e] = tmp; s++; e--; } return title; } }; ","date":"2015-08-27T13:22:04Z","permalink":"https://blog.coinidea.com/en/p/leetcode_168excel-sheet-column-title/","title":"[leetcode_168]Excel Sheet Column Title"},{"content":"A simple simulation problem \u0026ndash; merge intervals.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Solution { public: string convertIntToStr(int num) { char str[255]; sprintf(str, \u0026#34;%d\u0026#34;, num); return str; } vector\u0026lt;string\u0026gt; summaryRanges(vector\u0026lt;int\u0026gt;\u0026amp; nums) { vector\u0026lt;string\u0026gt; ranges; ranges.clear(); if (nums.size() \u0026lt;= 0) { return ranges; } int start = nums[0]; int end = nums[0]; for (int i = 1;i \u0026lt; nums.size(); i++) { if (nums[i] - nums[i-1] == 1) { end = nums[i]; } else { string item = convertIntToStr(start); if (end == start) { ranges.push_back(item); } else { item += \u0026#34;-\u0026#34;; item += convertIntToStr(end); ranges.push_back(item); } start = nums[i]; end = start; } } string item = convertIntToStr(start); if (end == start) { ranges.push_back(item); } else { item += \u0026#34;-\u0026#34;; item += convertIntToStr(end); ranges.push_back(item); } return ranges; } }; ","date":"2015-08-27T13:17:31Z","permalink":"https://blog.coinidea.com/en/p/leetcode-228-summary-ranges/","title":"[LeetCode 228] Summary Ranges"},{"content":"CoinLife is a mobile WebApp independently developed by me, serving as a life assistant. WebAPP - Details | Android - Details\nIt has the following features:\nProject Management Bill Management Menu Management ","date":"2015-08-23T16:02:33Z","permalink":"https://blog.coinidea.com/en/p/coinlife--life-assistant/","title":"CoinLife -- Life Assistant"},{"content":"The World Wind GitHub source code used in this article can be downloaded at: https://github.com/hujiulin/WorldWind\nWorld Wind, led by the National Aeronautics and Space Administration (NASA), is an open-source geographic information system project developed collaboratively by developers worldwide. Developed by NASA Research and promoted by NASA Learning Technologies, it displays satellite imagery, electronic maps, terrain maps, and other geographic data on a 3D digital globe. It is designed for data integration across industries, supports WMS, WFS, WMTS, and other services, and is an excellent 3D client framework rendering engine. It uses XML for data description and configuration, offering good versatility and extensibility. World Wind currently has two versions: one based on .NET and one based on Java. Beyond its basic 3D globe functionality, World Wind is highly extensible with various plugins, supporting map data (satellite, electronic, terrain) published by Google, Microsoft, and others.\nThis article primarily addresses issues related to compiling, running, and fixing Chinese character encoding problems in World Wind.\nDownloading the Source Code, Configuring the Environment, and Compiling [Use an international network connection in case the servers are inaccessible] Downloading the Source Code WorldWind has both .Net and Java versions. NASA\u0026rsquo;s official website is: http://worldwind.arc.nasa.gov/java/\nIt provides Java version source code downloads.\n.Net version source code download:\nhttp://worldwind31.arc.nasa.gov/svn/trunk/WorldWind/\nThis provides an SVN repository. It is recommended to use SVN for downloading.\nNote: The above SVN was found through the wiki at http://www.worldwindcentral.com/wiki/Source_code.\nEnvironment Configuration DirectX9 must be installed beforehand. Compiling the Source Code Encoding issues: You will encounter many syntax errors related to strings, caused by file encoding problems.\nRight-click the file in VS Solution Explorer\nSelect \u0026ldquo;Open With\u0026rdquo;\nChoose \u0026ldquo;CSharp Editor with Encoding\u0026rdquo;\nSelect \u0026ldquo;Western European (Windows) - Code Page 1252\u0026rdquo;\nOpen the file \u0026ndash; no more garbled characters\nChange the file save encoding to UTF-8 via the File menu, then save the source file\nNote: About 6 files are affected.\nLoaderLock issue:\nMenu (Debug -\u0026gt; Exceptions) -\u0026gt; Exceptions window -\u0026gt; ManagedDebuggingAssistants -\u0026gt; Uncheck the LoaderLock option Registry permission issue:\nOpen the HtmlEditor project properties, and uncheck \u0026ldquo;Register for COM interop\u0026rdquo; in the \u0026ldquo;Build\u0026rdquo; tab Start running the program. Everything works fine, but transitioning from the initialization screen to the main program takes a long time. This is because the WorldWind server is not accessible from China. WorldWind provides an offline mode, and you can also modify the WMS server URL in the XML. The temporary solution used here is to comment out the following two lines of code:\nIn Worldwind -\u0026gt; PluginSDK -\u0026gt; ConfigurationLoader.cs, line 262:\nLine 321:\nWhen running the program, the Initializing splash screen is misaligned:\nDebugging reveals the issue is in worldwind.cs, in public MainApplication() [line 563]:\nUsing the splash form.\nSplash form:\nSplash constructor:\nYou can see the PictureBox code is commented out, and there is no PictureBox control on the form.\nIt uses: Adjust the image as shown above, and the program starts normally.\nDecided to back up the source code to Baidu Cloud and my own SVN server. [The upload to Baidu\u0026rsquo;s server did not succeed.]\nAfter migrating the WorldWind source code, an issue occurred:\nRebuilding and cleaning the project did not help.\nSolution:\nDelete this file:\nAfter deletion, reconfigure:\nIssue resolved.\nNote: The first time you run the program, you may need to wait a moment.\nIf references such as AVIFile.dll or FlickrNel.dll are missing, switch from Release mode to Debug mode to compile and run successfully. [The actual reason is that the corresponding DLLs need to be copied to the Release directory.]\nWhen fixing encoding issues, some people encounter a situation where the degree symbol in the main interface displays as garbled characters. This is because the encoding issue has not been fully resolved. Please save with \u0026ldquo;UTF-8 with BOM\u0026rdquo; in the \u0026ldquo;Advanced Save Options\u0026rdquo; to fix this.\nFiles with Encoding Issues: Project File WorldWind Compass3D.cs WorldWind GPSTrackerPlugin.WorldWind.cs WorldWindow WorldWindow.cs PluginSDK ConfigurationLoader.cs PluginSDK Angle.cs All encoding issues resolved:\nToday I compiled the code from SVN on an x64 machine, and the program would not run. The debugger showed the error:\n\u0026ldquo;Unhandled exception of type \u0026lsquo;System.BadImageFormatException\u0026rsquo;\u0026rdquo;\nSolution:\nChange from Any CPU or x64 mode to x86, then set the output path to \u0026ldquo;..binDebug\u0026rdquo; Rebuild the solution, compile and run successfully:\nOriginal link: http://cesiumcn.org/topic/206.html | Fast access in China: http://cesium.coinidea.com/topic/206.html\n","date":"2015-08-23T03:01:39Z","permalink":"https://blog.coinidea.com/en/p/worldwind1.-getting-started-with-worldwind--compiling-worldwind-and-fixing-encoding-issues/","title":"[WorldWind]1. Getting Started with WorldWind -- Compiling WorldWind and Fixing Encoding Issues"},{"content":"Convert a positive integer to binary, reverse the bit order, then output it as a decimal. A simulation problem.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public: uint32_t reverseBits(uint32_t n) { //To binary vector\u0026lt;int\u0026gt; nums(32, 0); int index = 0; while(n \u0026gt; 0) { nums[index++] = n % 2; n /= 2; } uint32_t ans = 0; for (int i = 0; i \u0026lt; nums.size(); i++) { ans += nums[i] * (uint32_t)pow(2.0, (int)(nums.size() - i - 1)); } return ans; } }; ","date":"2015-08-21T14:19:09Z","permalink":"https://blog.coinidea.com/en/p/leetcode_190reverse-bits/","title":"[leetcode_190]Reverse Bits"},{"content":"Determine whether a number n is a happy number. A happy number is defined by repeatedly summing the squares of its digits and checking if the result equals 1. If it doesn\u0026rsquo;t equal 1, repeat the process. In practice, this process will form a cycle. [This is a guess, not formally proven.]\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public: map\u0026lt;int, bool\u0026gt; flag; bool isHappy(int n) { if (n == 1) { return true; } map\u0026lt;int, bool\u0026gt;::iterator it = flag.find(n); if (it != flag.end()) { return false; } else { flag.insert(map\u0026lt;int, bool\u0026gt;::value_type(n, true)); } int tmpNum = 0; while (n \u0026gt; 0) { tmpNum += (n % 10) * (n % 10); n /= 10; } return isHappy(tmpNum); } }; ","date":"2015-08-21T14:17:58Z","permalink":"https://blog.coinidea.com/en/p/leetcode_202happy-number/","title":"[leetcode_202]Happy Number"},{"content":"Determine whether a number is a power of two. This can be done with bit manipulation \u0026ndash; just shift the bits.\nclass Solution { public: bool isPowerOfTwo(int n) { if (n \u0026lt;= 0) { return false; } while(true) { if (n == 1) { return true; } if (n % 2 != 0) { return false; } n \u0026gt;\u0026gt;= 1; } } }; ","date":"2015-08-21T14:16:13Z","permalink":"https://blog.coinidea.com/en/p/leetcode_231power-of-two/","title":"[leetcode_231]Power of Two"},{"content":"Determine whether a number is an ugly number. Solved using simulation.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public: bool isUgly(int num) { if (num \u0026lt;= 0) { return false; } while(true) { if(num%2 == 0) { num /= 2; } else if(num%3 == 0) { num /= 3; } else if(num%5 == 0) { num /= 5; } else { if (num == 1) { return true; } else { return false; } } } } }; ","date":"2015-08-21T14:14:39Z","permalink":"https://blog.coinidea.com/en/p/leetcode_263ugly-number/","title":"[leetcode_263]Ugly Number"},{"content":"Simulate a stack. Took a shortcut by using a vector to solve the problem.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Stack { public: vector\u0026lt;int\u0026gt; stack; // Push element x onto stack. void push(int x) { stack.push_back(x); } // Removes the element on top of the stack. void pop() { stack.pop_back(); } // Get the top element. int top() { return stack[stack.size() - 1]; } // Return whether the stack is empty. bool empty() { return stack.empty(); } }; ","date":"2015-08-21T14:13:33Z","permalink":"https://blog.coinidea.com/en/p/leetcode_225implement-stack-using-queues/","title":"[leetcode_225]Implement Stack using Queues"},{"content":"This is an interesting problem. Given a sorted array: 1,2,3,4,5,6,7, but it has been rotated, for example: 4,5,6,7,1,2,3. The task is to find the minimum element. An O(n) solution is always possible. I remember being asked a similar question during a Didi interview last year. I was sure it was binary search at the time, but felt I didn\u0026rsquo;t explain it clearly. This time, the approach is much clearer.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public: void binarySearch(vector\u0026lt;int\u0026gt;\u0026amp; nums, int left, int right, int \u0026amp;min) { if (left \u0026gt; right) { return ; } int mid = (left + right) / 2; if (nums[mid] \u0026gt;= min) { binarySearch(nums, left, mid - 1, min); binarySearch(nums, mid+1, right, min); } else { min = nums[mid]; binarySearch(nums, left, mid - 1, min); } } int findMin(vector\u0026lt;int\u0026gt;\u0026amp; nums) { int min = nums[0]; binarySearch(nums, 0, nums.size() - 1, min); return min; } }; ","date":"2015-08-21T14:12:27Z","permalink":"https://blog.coinidea.com/en/p/leetcode_153find-minimum-in-rotated-sorted-array/","title":"[leetcode_153]Find Minimum in Rotated Sorted Array"},{"content":"Determine whether two strings contain the same letters with the same frequency.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public: bool isAnagram(string s, string t) { vector\u0026amp;lt;int\u0026amp;gt; sCount(26, 0); for (int i = 0;i \u0026amp;lt; s.length();i++) { sCount[s[i] - \u0026#39;a\u0026#39;]++; } for (int i = 0;i \u0026amp;lt; t.length();i++) { sCount[t[i] - \u0026#39;a\u0026#39;]--; } for (int i = 0;i \u0026amp;lt; sCount.size(); i++) { if (0 != sCount[i]) { return false; } } return true; } }; ","date":"2015-08-21T14:08:11Z","permalink":"https://blog.coinidea.com/en/p/leetcode_242valid-anagram/","title":"[leetcode_242]Valid Anagram"},{"content":"Find the element that appears more than half the time in a given array (guaranteed to exist). Pay attention to whether the array length is odd or even. A hash map does the job.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public: int majorityElement(vector\u0026lt;int\u0026gt;\u0026amp; nums) { map\u0026lt;int, int\u0026gt; m_nums; m_nums.clear(); for (int i = 0; i \u0026lt; nums.size(); i++) { auto it = m_nums.find(nums[i]); if (it == m_nums.end()) { m_nums.insert({nums[i], 1}); } else { m_nums.erase(nums[i]); m_nums.insert({nums[i], ++(it-\u0026gt;second)}); } } for (auto it = m_nums.begin(); it != m_nums.end(); it++) { if (it-\u0026gt;second \u0026gt;= nums.size() / 2 + 1) { return it-\u0026gt;first; } } } }; ","date":"2015-08-19T13:03:04Z","permalink":"https://blog.coinidea.com/en/p/leetcode_169-majority-element/","title":"[leetcode_169] Majority Element"},{"content":"Determine whether a given array contains duplicate elements. A hash table solves this. I actually used a map, which is a binary search tree in C++. The O(log n) solution, so the performance isn\u0026rsquo;t the best.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public: bool containsDuplicate(vector\u0026lt;int\u0026gt;\u0026amp; nums) { map\u0026lt;int, bool\u0026gt; m_nums; m_nums.clear(); for (int i = 0; i \u0026lt; nums.size(); i++) { map\u0026lt;int, bool\u0026gt;::iterator it = m_nums.find(nums[i]); if (it == m_nums.end()) { m_nums.insert(map\u0026lt;int, bool\u0026gt;::value_type(nums[i], true)); } else { return true; } } return false; } }; ","date":"2015-08-19T13:01:16Z","permalink":"https://blog.coinidea.com/en/p/leetcode_217-contains-duplicate/","title":"[leetcode_217] Contains Duplicate"},{"content":"Find the actual column number represented by an Excel column label like \u0026ldquo;AB\u0026rdquo;. It\u0026rsquo;s essentially base-26 conversion.\n1 2 3 4 5 6 7 8 9 10 11 class Solution { public: int titleToNumber(string s) { int sum = 0; int size = s.length(); for (int i = 0; i \u0026lt; size; i++) { sum += (s[i] - \u0026#39;A\u0026#39; + 1) * (int)pow(26.0, (size - i - 1)); } return sum; } }; ","date":"2015-08-19T12:59:48Z","permalink":"https://blog.coinidea.com/en/p/leetcode_171-excel-sheet-column-number/","title":"[leetcode_171] Excel Sheet Column Number"},{"content":"Inverting a binary tree is essentially a post-order traversal of the tree with swapping of left and right child nodes.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public: void swap(TreeNode \u0026amp; left, TreeNode *\u0026amp; right) { TreeNode * tmp = left; left = right; right = tmp; } TreeNode * invertTree(TreeNode* root) { if (root == NULL) return NULL; if (root-\u0026gt;left != NULL) invertTree(root-\u0026gt;left); if (root-\u0026gt;right != NULL) invertTree(root-\u0026gt;right); swap(root-\u0026gt;left, root-\u0026gt;right); return root; } }; ","date":"2015-08-19T12:58:35Z","permalink":"https://blog.coinidea.com/en/p/leetcode_226invert-binary-tree/","title":"[leetcode_226]Invert Binary Tree"},{"content":"Find the lowest common ancestor of two nodes in a binary tree. I\u0026rsquo;ve done similar problems before, but it\u0026rsquo;s been a while since I last solved algorithm problems, so I thought it through again. The approach is depth-first search to find the two paths, then find their intersection. I was initially worried about time limit exceeded, but the AC was quite fast.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Solution { public: bool isFind; vector\u0026lt;TreeNode *\u0026gt; pV, qV; void FindK(TreeNode *node, TreeNode* k, vector\u0026lt;TreeNode *\u0026gt; \u0026amp;kV) { kV.push_back(node); if (isFind || node == k) { isFind = true; return; } if (NULL != node-\u0026gt;left) { FindK(node-\u0026gt;left, k, kV); if (isFind) { return; } kV.pop_back(); } if (NULL != node-\u0026gt;right) { FindK(node-\u0026gt;right, k, kV); if (isFind) { return; } kV.pop_back(); } } TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { if (NULL == root) { return root; } pV.clear(); qV.clear(); isFind = false; FindK(root, p, pV); isFind = false; FindK(root, q, qV); int i = 0; int minSize = pV.size() \u0026gt; qV.size() ? qV.size() : qV.size(); for (i = 0;i \u0026lt; minSize; i++) { if (pV[i] != qV[i]) { break; } } return pV[i - 1]; } }; ","date":"2015-08-19T12:57:17Z","permalink":"https://blog.coinidea.com/en/p/leetcode_235lowest-common-ancestor-of-a-binary-search-tree/","title":"[leetcode_235]Lowest Common Ancestor of a Binary Search Tree"},{"content":"Count the number of 1s in the binary representation of an integer. A straightforward simulation.\n1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public: int hammingWeight(uint32_t n) { int count = 0; while(n \u0026gt; 0) { count += n%2; n /= 2; } return count; } }; ","date":"2015-08-19T12:55:17Z","permalink":"https://blog.coinidea.com/en/p/leetcode_191-number-of-1-bits/","title":"[leetcode_191] Number of 1 Bits"},{"content":"Delete a specified node in a singly linked list. When I first read the problem, I thought at least both the head node and the target node should be given. But after guessing, I realized the problem likely requires copying the values of subsequent nodes forward to overwrite, rather than performing a true linked list deletion.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public: void deleteNode(ListNode* node) { ListNode * next = node-\u0026gt;next; ListNode * before = NULL; while(next != NULL) { node-\u0026gt;val = next-\u0026gt;val; before = node; node = next; next = next-\u0026gt;next; } before-\u0026gt;next = NULL; } }; ","date":"2015-08-19T12:53:27Z","permalink":"https://blog.coinidea.com/en/p/leetcode_237delete-node-in-a-linked-list/","title":"[leetcode_237]Delete Node in a Linked List"},{"content":"I couldn\u0026rsquo;t figure out the O(1) approach, so here\u0026rsquo;s the simulation method: Repeatedly sum all the digits until the sum is less than 10.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public: int addDigits(int num) { int sum = 0; while(num \u0026gt; 0) { sum += num % 10; num /= 10; } if (sum \u0026gt;= 10) { return addDigits(sum); } else { return sum; } } }; ","date":"2015-08-19T12:38:32Z","permalink":"https://blog.coinidea.com/en/p/leetcode_258add-digits/","title":"[leetcode_258]Add Digits"},{"content":" There are two mainstream Android development environments: 1. Android Studio by Google The first one sounds very professional just from the name, and it\u0026rsquo;s made by Google. It\u0026rsquo;s fairly stable now. However, due to certain conditions in our country, *.google.com is very hard to access, and it\u0026rsquo;s been getting worse recently. Android Studio is heavily dependent on network access. After downloading and using it, I found it inconvenient. For users with easy internet access, I recommend considering it. Domestic download link: http://www.android-studio.org/\n2. Eclipse Eclipse is currently a very popular IDE for Android development.\nI recommend a very professional domestic website: http://www.androiddevtools.cn/\nThis website covers all the Android-related resources you\u0026rsquo;ll need.\nThe required setup is as follows:\nJava\nOfficial site: http://www.java.com/zh_CN/\nAndroiddevtools link: http://www.androiddevtools.cn/ Select Android SDK Tools -\u0026gt; JDK\nEclipse\nOfficial site: http://www.eclipse.org/downloads/\nRecommended: IDE For Java EE. Eclipse has different versions; I downloaded the latest one at the time, Mars.\nADT (Android Development Tools): Eclipse Plugin\nEclipse is a powerful, extensible, open-source IDE with many plugins. ADT is one of them.\nAndroiddevtools link: http://www.androiddevtools.cn/ Select Android SDK Tools -\u0026gt; ADT Plugin\nHow to install ADT:\nDownload the latest rar archive to your local machine. Open Eclipse, go to Help -\u0026gt; Install New Software Click Archive, select the local archive, and set the Name to ADT. After installing ADT, if these two icons don\u0026rsquo;t appear in Eclipse\u0026rsquo;s toolbar, go to Eclipse -\u0026gt; Window -\u0026gt; Perspective -\u0026gt; Customize Perspective and check the boxes. One icon manages the SDK and the other manages AVDs. AVD stands for Android Virtual Device - a simulated Android device.\nSelect All, click Finish. Android SDK-Tools\nAndroiddevtools link: http://www.androiddevtools.cn/ Select Android SDK Tools -\u0026gt; SDK Tools\nDownload and install to your chosen directory. The final directory size can be quite large, so make sure you have enough space.\nIn Eclipse -\u0026gt; Preferences, specify the SDK Location.\nAndroid SDK\nYou can see my Location shows Android 4.3.1, but yours might not have anything. That\u0026rsquo;s because you need to install specific SDK packages.\nAndroiddevtools link: http://www.androiddevtools.cn/ Select Android SDK Tools -\u0026gt; SDK\nDownload the packages. I recommend downloading version 4.0.0 or later.\nCopy the extracted folder into the Platforms folder inside your Android SDK-Tools directory. Create the folder if it doesn\u0026rsquo;t exist.\nAndroid Build-Tools\nThese are the Build-Tools needed for Android development. Download and extract, then copy or move the entire extracted folder to your-sdk-path/build-tools.\nAndroiddevtools link: http://www.androiddevtools.cn/ Select Android SDK Tools -\u0026gt; Build-Tools\nAndroid Platform-Tools\nThis is the package containing adb, fastboot, and other tools. Place the extracted platform-tools folder in the android sdk root directory, and add the directory containing adb to your system PATH so you can access adb, fastboot, and other tools directly from the command line.\nAndroiddevtools link: http://www.androiddevtools.cn/ Select Android SDK Tools -\u0026gt; Platform-Tools\nAndroid SDK System-Images\nThese are the system images needed when creating emulators - they\u0026rsquo;re what you select for the CPU/ABI option when creating an emulator. Download and extract, then copy or move the entire extracted folder to your-sdk-path/system-images. If the system-images directory doesn\u0026rsquo;t exist, create it first. Then open SDK Manager, go to the Tools menu, select Options to open the Android SDK Manager Settings dialog, click Clear Cache, and restart Eclipse (or Android Studio) and SDK Manager.\nAndroiddevtools link: http://www.androiddevtools.cn/ Select Android SDK Tools -\u0026gt; System-Images\nAVD\nCreate an AVD for debugging.\nClick the AVD icon, then click Create. Configure it according to your needs.\nCreate a New HelloWorld Project\nIn Eclipse: File -\u0026gt; New -\u0026gt; Other -\u0026gt; Android Application Project, then keep clicking Next and Finish.\nHere\u0026rsquo;s the result:\n","date":"2015-08-17T04:45:38Z","permalink":"https://blog.coinidea.com/en/p/setting-up-an-android-development-environment/","title":"Setting Up an Android Development Environment"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include \u0026lt;iostream\u0026gt; using namespace std; int main() { int n; // The longest row of the diamond has n characters, and n must be odd because n = 2*k + 1 cin \u0026gt;\u0026gt; n; int cn = 1; bool isUp = true; for (int i = 1; i \u0026lt;= n; i++) { for (int j = 1; j \u0026lt;= (n - cn) / 2; j++) { cout \u0026lt;\u0026lt; \u0026#34; \u0026#34;; } for (int j = 1; j \u0026lt;= cn; j++) { cout \u0026lt;\u0026lt; \u0026#34;*\u0026#34;; } for (int j = 1; j \u0026lt;= (n - cn) / 2; j++) { cout \u0026lt;\u0026lt; \u0026#34; \u0026#34;; } cout \u0026lt;\u0026lt; endl; if (cn \u0026gt;= n) { isUp = false; } if (isUp) { cn += 2; } else { cn -= 2; } } return 0; } ","date":"2015-07-27T02:04:30Z","permalink":"https://blog.coinidea.com/en/p/c-drawing-a-diamond-shape/","title":"[C++] Drawing a Diamond Shape"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include \u0026lt;iostream\u0026gt; using namespace std; int main() { char filename[255]; cin \u0026gt;\u0026gt; filename; FILE * pFile = fopen(filename, \u0026#34;r\u0026#34;); fseek(pFile, 0L, SEEK_END); long count = ftell(pFile); cout \u0026lt;\u0026lt; \u0026#34;Byte count=\u0026#34; \u0026lt;\u0026lt; count \u0026lt;\u0026lt; endl; fclose(pFile); return 0; } ","date":"2015-07-26T02:04:30Z","permalink":"https://blog.coinidea.com/en/p/c-open-a-txt-file-by-input-filename-and-count-its-bytes/","title":"[C++] Open a TXT File by Input Filename and Count Its Bytes"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 \u0026lt;script type=\u0026#34;text/javascript\u0026#34;\u0026gt; var arr = new Array(); var flag = new Array(1001); for (var i = 1; i \u0026lt;= 1000; i++) { flag[i] = 0; } for (var i = 2; i \u0026lt;= 1000; i++) { if (flag[i] == 0) { flag[i] = 1; arr.push(i); for (var j = 1; j * i \u0026lt;= 1000; j++) { flag[j*i] = 1; } } } var ans = \u0026#34;2\u0026#34;; for (var i = 1; i \u0026lt; arr.length; i++) { ans = ans + \u0026#34;,\u0026#34; + arr[i].toString(); } alert(ans); \u0026lt;/script\u0026gt; This uses the Sieve of Eratosthenes, which has good performance. Tested and working in Chrome. Hope it helps!\nThis was my answer on Baidu Zhidao (a Q\u0026amp;A platform).\n","date":"2015-07-26T02:01:42Z","permalink":"https://blog.coinidea.com/en/p/javascript-finding-prime-numbers-up-to-n/","title":"[JavaScript] Finding Prime Numbers Up to N"},{"content":"Wednesday, November 28, 2012 - Prelude to Purchase and Preface\nOn November 11th this year, my roommate Xingxing owed me 30 yuan. I told him to get me a Singles\u0026rsquo; Day gift instead of paying me back. He asked what I wanted. At the time, I was really into reading the Steve Jobs biography, so I figured a Peking University student would know some great books. I asked him to buy me a book and recommend something. He said GEB was good. I was taken aback - that\u0026rsquo;s supposed to be a book for mathematical logic. After thinking about it, I asked him to get me \u0026ldquo;On the Crest of the Wave\u0026rdquo; instead. But I still went and searched for GEB. The review on Dangdang said: \u0026ldquo;This is an unprecedented masterpiece and an outstanding popular science work. With carefully designed and ingenious writing, it provides accessible introductions to many profound theories in mathematical logic, computability theory, artificial intelligence, and other fields. The relaxed, humorous, and flowing prose conceals a wealth of subtext, with ideas cross-referencing and interconnecting, weaving into a complex, invisible network. Readers can\u0026rsquo;t see it, but they can sense its presence and realize the author has sprayed it deliberately.\u0026rdquo;\nOn November 22nd, I purchased the book from Dangdang.\nOn November 28th, I began reading. Author: [American] Hou Shida. Is the author Chinese? I started reading with this question in mind. Ever since the Jobs biography, I\u0026rsquo;ve made a point of reading prefaces first. GEB\u0026rsquo;s preface is 38 pages long.\nFrom the preface, I learned that the Chinese edition of this book was made possible by Professors Wu Yunceng and Ma Xiwen of Peking University. I discovered that Hou Shida is not actually Chinese - he is Douglas Richard Hofstadter. He\u0026rsquo;s a remarkable person, not only for his achievements in mathematics and computer science, but I personally believe that through his efforts in facilitating GEB translations into multiple languages, he is truly a linguist. \u0026ldquo;Hou Shida\u0026rdquo; is the Chinese name he gave himself, and he even wrote a preface for the Chinese edition.\nThe Chinese edition is by no means a simple English-to-Chinese translation. I believe that given the author\u0026rsquo;s linguistic mastery, combined with the support of Peking University and the Commercial Press, this book is truly a masterpiece in Chinese, achieving Yan Fu\u0026rsquo;s three fundamental standards: faithfulness, expressiveness, and elegance. I also appreciate their views on translating scientific papers.\nFor example: \u0026ldquo;a man, a plan, a canal: Panama\u0026rdquo; - should it be translated as \u0026ldquo;an engineer designed the Panama Canal\u0026rdquo;? But as a computer science student, I was amazed to discover that this English sentence is a palindrome! So why not use the Chinese palindrome equivalent?\nAbout GEB: Godel, Escher, Bach: an Eternal Golden Braid\nThe Chinese title: the initials of the Chinese transliteration correspond to the English acronym GEB.\nOh, and there\u0026rsquo;s another artistic touch:\nThe 3D projections of these two small blocks spell out GEB and EGB (the second half of the book).\nThe Peking University translation team went even further: the Chinese title embeds both the Chinese and English GEB.\nThursday, December 6, 2012 - Introduction: A Musico-Logical Offering\nI\u0026rsquo;ve been too busy lately. After finishing the Steve Jobs biography and \u0026ldquo;On the Crest of the Wave,\u0026rdquo; I wanted to focus on GEB. But on one hand I was too busy, and on the other, I realized that apart from having some foundation in computer science, I\u0026rsquo;m really clueless about other fields, especially music. Unlike the previous two books, GEB requires you to actively think and understand. It\u0026rsquo;s filled with logical proofs, paradoxes that appear at every turn, and casual references to palindromes in computer science, isomorphism in discrete mathematics, and rest vs. motion in physics.\nToday I finally finished the introduction. The introduction revolves around Bach\u0026rsquo;s Musical Offering, cleverly titled \u0026ldquo;A Musico-Logical Offering,\u0026rdquo; and then discusses Bach, Escher, and Godel - three great masters.\nCanon and Fugue:\nAs a music novice, I had only heard of canons before - I\u0026rsquo;d never even heard of fugues. But when you try to understand them, you realize Bach was truly a genius. From the perspective of symmetrical beauty, even without hearing his compositions, looking at their structure alone, you can tell they must be beautiful.\nThe fundamental concept of a canon is a single theme accompanied by itself. Different voices enter and each presents a \u0026ldquo;copy\u0026rdquo; of the theme. The simplest form is a round. More complex canons become increasingly intricate, interweaving not only in time but also in pitch. The first voice might present the theme in C, while the second voice enters with the same theme in G (a fifth above C), and the third in D (a fifth above G) - creating something like an arithmetic sequence. Just looking at this structure, I can tell it would sound wonderful. There\u0026rsquo;s an even more complex technique called inversion, which produces a melody that jumps down whenever the original theme jumps up, by the same number of semitones. Then comes the most magical part - retrograde. The theme is played backwards in time, creating what\u0026rsquo;s called a crab canon. Every type of copy preserves the information of the original theme, and the theme can be recovered from any copy. This information-preserving transformation is called isomorphism.\nJust on Thursday, my professor asked me what graph isomorphism is. I said it can be \u0026ldquo;stamped over\u0026rdquo;! Then what about subgraph isomorphism?\nFugues are similar to canons but less strict.\nTo transition to the great artist Escher, I must mention the endlessly rising canon. This canon begins in C major, but by the time it nears the end, it\u0026rsquo;s in D minor - a fifth higher, a change so subtle that listeners barely notice. At the so-called \u0026ldquo;ending,\u0026rdquo; Bach cleverly loops it back to the beginning, creating an endless cycle.\n\u0026ldquo;Seek, and ye shall find.\u0026rdquo;\nIf Bach played this endlessly rising strange loop, then Escher painted it! The image below is \u0026ldquo;Waterfall,\u0026rdquo; where six distinct stages demonstrate the strange loop.\n\u0026ldquo;Ascending and Descending\u0026rdquo; demonstrates the strange loop in just four stages, though more loosely.\nThursday, December 7, 2012 - Introduction: A Musico-Logical Offering\nNow let\u0026rsquo;s talk about the greatest mathematician, Godel. The strange loops of Bach and Escher contain a conflict between the finite and the infinite, with a strong sense of paradox. Is there something wrong with mathematics?\nThere\u0026rsquo;s a paradox called the Epimenides paradox: Epimenides was a Cretan who said, \u0026ldquo;All Cretans are liars.\u0026rdquo;\nThis statement can be understood as: \u0026ldquo;This sentence is false.\u0026rdquo;\nIf you assume it\u0026rsquo;s true, it concludes that it\u0026rsquo;s false. If you assume it\u0026rsquo;s false, it concludes that it\u0026rsquo;s true.\nIn 1931, Godel published Godel\u0026rsquo;s theorem, which in essence states that no matter what axiomatic system you design, provability is always weaker than truth.\nEverything can perhaps be understood as originating from the strange loop of \u0026ldquo;self-reference.\u0026rdquo; Or a loop, like the following example with two sentences:\nThe sentence below is false.\nThe sentence above is true.\nRussell and Whitehead devoted themselves to eliminating such strange loops. \u0026ldquo;Principia Mathematica\u0026rdquo; is a rather peculiar bottom-up axiomatic system that appears to eliminate strange loops.\nHilbert\u0026rsquo;s Program:\nHilbert hoped someone could prove that Principia Mathematica was both consistent and complete - that is, internally contradiction-free while being able to prove all theorems within it. This has a flavor of circular reasoning, somewhat like forcing someone to lift themselves up by their own bootstraps.\nUnfortunately, Godel proved that \u0026ldquo;no axiomatic system can produce all number-theoretic truths, unless it is an inconsistent system.\u0026rdquo;\nNow let\u0026rsquo;s discuss what intelligence is:\nResponding flexibly to situations. Taking advantage of opportunities. Making sense of ambiguous or contradictory information. Recognizing what is important in a situation and what is secondary. Finding similarities between situations despite differences. Finding differences between things connected by similarities. Synthesizing new concepts from old ones, combining them in new ways. Coming up with entirely new ideas. Friday, December 8, 2012 - Three-Part Invention: The MU Puzzle\nNow let\u0026rsquo;s discuss history\u0026rsquo;s most famous Zeno\u0026rsquo;s paradox: motion is impossible.\nThe swift-footed Achilles wants to chase a tortoise. He gives the tortoise a 10-meter head start. Every time Achilles covers half the remaining distance, the tortoise moves forward some distance. So Achilles keeps closing the gap but can never catch the tortoise.\nA more general understanding of this paradox: a person walks from point A to point B, each time covering one-tenth of the remaining distance, so they can never reach point B.\nThe key issue in this paradox is time. Assume the distance is 10 meters and the speed is 10 meters per second. The reason they can\u0026rsquo;t arrive is that each step takes 0.1, 0.01, 0.001\u0026hellip; seconds. The total is only 0.11111\u0026hellip; seconds, not even 1 second, so of course they can\u0026rsquo;t make it.\nLater I looked up more about Zeno\u0026rsquo;s paradoxes. Besides Achilles and the tortoise, there\u0026rsquo;s also the \u0026ldquo;flying arrow\u0026rdquo; example. I won\u0026rsquo;t describe it in detail here, but I think the physics principle that \u0026ldquo;rest is relative, motion is absolute\u0026rdquo; can explain this paradox.\nA distinctive feature of this book is that at the beginning of each new chapter, the author uses Achilles and the Tortoise to have a conversation as a way to introduce the topic.\nChapter 1 covers the MU puzzle. With a foundation in discrete mathematics and mathematical logic, it\u0026rsquo;s not too difficult to understand. But there are indeed many clever and thought-provoking aspects.\nStarting string: MI. Goal: construct the target string MU.\nThe rules:\nIf a string you own ends in I, you can add a U at the end. If you have Mx, then Mxx is also yours. If III appears in one of your strings, you can replace III with U to get a new string. If UU appears in your string, you can drop it. The difference between humans and machines when constructing MU: machines don\u0026rsquo;t get tired but they can\u0026rsquo;t think, so they\u0026rsquo;ll keep searching according to the rules. Humans are different - they use insight to search for the string, or complain that it can\u0026rsquo;t be found.\nMore directly, humans have the ability to jump out! To step outside the system and look at something else. Machines can\u0026rsquo;t do this.\nDecision procedure: We define a decision procedure as one that determines, in finite time, whether a string is a theorem or not. Generally speaking, we can derive whether a string is a theorem, but it might take infinite time.\nSuppose there\u0026rsquo;s a demon with unlimited time. If it were to solve the MU puzzle, it might:\nApply every applicable rule to the axiom MI, producing two new theorems: MIU, MIII. Apply all applicable rules to the theorems from step 1, producing new theorems: MIIU, MIUIU, and MIIII. Apply the same rules to the theorems from step 2, producing more new theorems. \u0026hellip; What the Tortoise said to Achilles.\nThis conversation may seem absurd, but it gave me a kind of revelation - even a shock! What does it mean to prove! To reason! To infer! I also witnessed the power of hypothetical propositions.\nHere\u0026rsquo;s a small fragment of an argument:\nThings that are equal to the same thing are also equal to each other. The two sides of this triangle are equal to the same thing. The two sides of this triangle are equal to each other. Readers of Euclid would consider Z a logical conclusion, so anyone who accepts A and B as true must accept Z as true.\nBut consider two objections:\nSomeone who doesn\u0026rsquo;t accept A and B as true, but agrees that \u0026ldquo;if A and B are true, then Z is true.\u0026rdquo;\nSomeone who accepts A and B as true, but doesn\u0026rsquo;t accept that \u0026ldquo;if A and B are true, then Z is true.\u0026rdquo;\nCase 1 is understandable; let\u0026rsquo;s set it aside for now.\nLet\u0026rsquo;s discuss case 2: how would you try to convince someone holding view 2 to accept the argument A-B-Z?\nLet\u0026rsquo;s try this approach:\nDefine the hypothetical proposition \u0026ldquo;if A and B are true, then Z is true\u0026rdquo; as proposition C.\nDoes the following proof work?\nA B C Z\nOK! But what about someone who questions the hypothetical proposition \u0026ldquo;if A, B, and C are true, then Z is true\u0026rdquo;?\nDo we need to define yet another hypothetical proposition D? An infinite loop? Doesn\u0026rsquo;t this remind you of Bach\u0026rsquo;s endlessly rising canon?\nWhat a delightful introductory example!\nLet\u0026rsquo;s define a simple system: the pq system:\nThree symbols: p q -\nDefinition of axioms: As long as x consists solely of a string of hyphens, then x-qxp- is an axiom.\nRule: Assuming x, y, and z each represent specific strings containing only hyphens, and assuming xqypz is a known axiom, then x-qypz- is a theorem.\nGiven a string, how do you determine whether it\u0026rsquo;s a theorem?\nBottom-up: this method is similar to the MU puzzle approach described earlier and won\u0026rsquo;t be elaborated here.\nTop-down: repeatedly find its predecessor string according to the rules, and verify whether that string is an axiom. (Of course, we have an obvious way to determine whether a string is an axiom - otherwise, as Hofstadter says, all hope would be lost.)\nUpon careful study of the pq system, through insight one can discover a pattern: if it\u0026rsquo;s a theorem, it must be of the form xqypz, where |x| = |y| + |z|.\nIn fact, this is something mentioned earlier in these notes called isomorphism: two complex structures can be mapped to each other, with every part of each structure having a corresponding part in the other. We\u0026rsquo;ve assigned real-world meaning to a series of simple symbols: addition.\nThis is our own projection, of course. You could say q corresponds to \u0026ldquo;horse,\u0026rdquo; p to \u0026ldquo;happiness,\u0026rdquo; and - to \u0026ldquo;apple.\u0026rdquo; But the resulting theorems would be bizarre statements about horses, happiness, and apples with no real-world significance. Of course, our system is predefined - we can\u0026rsquo;t assume that just because it can represent addition, we can fantasize that x-q-x-p-x- is a theorem because 6 = 2+2+2. That\u0026rsquo;s correct in real life but clearly doesn\u0026rsquo;t hold in our pq system.\nThis isomorphism isn\u0026rsquo;t unique either - for instance, you could map q to subtraction and p to the equals sign, and it would also work. These simple but (in my view) fascinating examples show us the difference between formal systems and reality.\nFinally, here\u0026rsquo;s the example that shocked me the most:\nWhat is 12 times 12? 144? Correct! If we doubt it, we can count the cells in a 12-by-12 grid.\nBut what about 123456789 times 987654321? We can\u0026rsquo;t exactly count that. Who can say the value is truly what it is? How do you prove it?\nHere\u0026rsquo;s a theorem called Euclid\u0026rsquo;s theorem: regarding the proposition that there are infinitely many prime numbers, no counting process can prove its truth or falsity. No matter how many primes we count, we can never determine whether the number of primes is finite or infinite.\nEuclid gave a brilliant proof - at least I think everyone thought so at the time and for a long time after.\nPick a number N, compute N!, then form a new number N!+1. This number is not divisible by any number from 2, 3, 4, 5, 6, 7, 8, 9, \u0026hellip; N.\nThere are only two outcomes: N!+1 is either itself a prime, or its smallest prime factor is greater than N. In either case, we\u0026rsquo;ve found a prime larger than N.\nSo when we want to bypass the concept of infinity to prove something, we can use words like \u0026ldquo;all\u0026rdquo; - finite in themselves but embodying the concept of infinity.\nLet\u0026rsquo;s look at one of Escher\u0026rsquo;s tessellations.\n","date":"2015-07-25T07:04:11Z","permalink":"https://blog.coinidea.com/en/p/reading-notes-godel-escher-bach-an-eternal-golden-braid/","title":"[Reading Notes] Godel, Escher, Bach: An Eternal Golden Braid"},{"content":"After being on the other side of the table many times, I finally got to conduct an interview myself. Although I\u0026rsquo;m still a junior developer, I still want to document this experience.\nOverall, I didn\u0026rsquo;t speak at first, but when I noticed the candidate\u0026rsquo;s resume mentioned the TP framework and Yii framework, I couldn\u0026rsquo;t help asking a few questions about how these frameworks handle XSS and CSRF prevention.\nWhen the conversation turned to how to determine whether two numbers in an array sum up to a target value, I asked a few more questions.\nAll in all, I\u0026rsquo;m fairly satisfied with my first interview. However, I might have been a bit too aggressive in my questioning. I should take note and work on improving that :).\n","date":"2015-07-21T16:08:32Z","permalink":"https://blog.coinidea.com/en/p/reflections-on-my-first-interview-as-interviewer/","title":"Reflections on My First Interview (as Interviewer)"},{"content":"I previously wrote Defending Against CSRF and XSS in Yii [Part 1], but when it came to actual testing, there was a requirement to filter out special characters such as :, :, \u0026ldquo;, \u0026lt;, \u0026gt;, %, etc.\nYii\u0026rsquo;s CHtml::purifier actually only filters HTML, and CHtml::encode essentially calls htmlspecialchars:\nhtmlspecialchars only converts \u0026lt;, \u0026gt;, single quotes, double quotes, and \u0026amp; htmlentities converts all HTML entities As you can see, PHP\u0026rsquo;s built-in functions cannot filter all special characters. The approach I took was to create a new Filter class within the Yii framework and write a custom specialchar function, allowing you to replace characters as needed. For better performance, it can be defined as public static.\n1 2 3 4 5 6 7 class Filter { public static function ReplaceSpecialChar($str) { $str=str_replace(\u0026#34;:\u0026#34;,$str); //TODO: replace other chars $str = htmlspecialchars($str); return $str; } } ","date":"2015-07-21T16:04:21Z","permalink":"https://blog.coinidea.com/en/p/yii-defending-against-csrf-and-xss-in-yii-part-2/","title":"[Yii] Defending Against CSRF and XSS in Yii [Part 2]"},{"content":"CSRF stands for Cross-Site Request Forgery, and XSS stands for Cross-Site Scripting. To be honest, I only recently encountered these for the first time. After building a website with Yii and scanning it with testing software (e.g., IBM AppScan), two relatively common and serious issues were found: CSRF and XSS. So how do we fix them?\n\u0026ndash; CSRF\nReference: http://www.crarun.com/article-7.html\nYii supports CSRF configuration in its config file. Once configured, it embeds a hidden token with a hash key value in forms, and the server verifies whether each request is authorized through this token.\n1 2 3 4 5 6 \u0026#39;components\u0026#39;=\u0026gt;array( \u0026#39;request\u0026#39;=\u0026gt;array( // Enable Yii Validate CSRF Token \u0026#39;enableCsrfValidation\u0026#39; =\u0026gt; true, ), ), In practice, because I was using an older version of Yii, the framework didn\u0026rsquo;t automatically create the input element in forms, so I had no choice but to create it manually by inserting the following code:\n1 \u0026lt;input type=\u0026#34;hidden\u0026#34; value=\u0026#34;\u0026lt;?php echo Yii::app()-\u0026gt;getRequest()-\u0026gt;getCsrfToken(); ?\u0026gt;\u0026#34; name=\u0026#34;YII_CSRF_TOKEN\u0026#34; /\u0026gt; Another issue arose: since CSRF wasn\u0026rsquo;t considered thoroughly early on, the entire system contained numerous AJAX POST requests, meaning lots of JS code had POST submissions. However, Yii\u0026rsquo;s view rendering doesn\u0026rsquo;t affect code inside .js files - even if you add the above code in a .js file, PHP won\u0026rsquo;t produce any output. So I came up with a workaround:\nAdd the following code to JS POST submissions:\n1 $(\u0026#34;input[name=\u0026#39;YII_CSRF_TOKEN\u0026#39;]\u0026#34;).val() Then add the hidden input in the PHP view. However, this also reveals a limitation - it doesn\u0026rsquo;t fully prevent CSRF. The optimal solution would be to embed authorization in each user\u0026rsquo;s session.\n\u0026ndash; XSS\nWhen searching for solutions to this problem, a common question is: at which stage should string filtering be done - submission, storage, or display? I saw an answer on SegmentFault that said both are essential: one prevents malicious data from entering the database, and the other prevents it from being executed.\nIn my opinion, front-end user validation during submission is essential for good user experience. However, server-side validation is still a must, since programs can bypass the front end.\nShould we also filter during display? I recommend yes - it adds an extra layer of safety to prevent attacks from taking effect.\nHow to do it? Yii provides CHtml and CHTMLPurifier for filtering. On GitHub, many people have open-sourced good front-end libraries for filtering - just search for them.\n","date":"2015-07-19T02:59:44Z","permalink":"https://blog.coinidea.com/en/p/yii-defending-against-csrf-and-xss-in-yii-part-1/","title":"[Yii] Defending Against CSRF and XSS in Yii [Part 1]"},{"content":"I\u0026rsquo;ve been building my own open-source web component library recently, keeping it as simple as possible for my own learning, while also sharing some insights with other beginners. GitHub download link: https://github.com/hujiulin/coinjs\n- ProgressBar - FloatBox (Popup Dialog) - ImageWall (Image Banner) - Nav (Pure CSS Navigation Bar) - ScrollImage (Scrolling Images) ","date":"2015-07-03T17:06:30Z","permalink":"https://blog.coinidea.com/en/p/coinjs-an-open-source-web-component-library/","title":"CoinJS - An Open Source Web Component Library"},{"content":"I\u0026rsquo;ve been so busy lately with graduation, moving, and starting a new job that I haven\u0026rsquo;t had a chance to sit down and write properly. I feel like I\u0026rsquo;ve become a full-fledged househusband - buying appliances, grocery shopping, cooking, getting takeout, doing housework, the whole nine yards.\nI recently posted something on social media: \u0026ldquo;Once this door closes today, it\u0026rsquo;ll be two different worlds from now on.\u0026rdquo;\nThe zeroth anniversary of graduation marks the end of my 23-year student career (my mom says I started kindergarten at two and a half) and the beginning of year zero of my working life. Over the past year-plus of job hunting, I\u0026rsquo;ve been through the wringer - weathered all kinds of storms - but gradually got used to it.\nWhat is growing up?\nGrowing up means:\nWhen you walk into a supermarket, you discover that even the cheapest bottle of cooking oil costs 30-40+ yuan; a single bowl costs 10 yuan. You learn to budget carefully. You boil an egg first thing in the morning. When cycling, don\u0026rsquo;t wear a backpack - it makes your back sweat like crazy. Just put it in the basket. You can tell the difference between electric bikes with removable lithium batteries and those with non-removable lead-acid batteries. The lithium battery ones don\u0026rsquo;t look as nice. You carefully observe Beijing\u0026rsquo;s elaborate transportation system and discover there are bike lanes with well-designed merging and diverging. Follow the bike lanes and you can ride smoothly to your destination, even through overpasses. This is probably a lot like life itself. You can soak the shower head in diluted disinfectant for effective sterilization. Yeah, I\u0026rsquo;m just broke. I don\u0026rsquo;t know what the future holds. I\u0026rsquo;ve been wanting to learn Android development lately and check out the book \u0026ldquo;First Line of Code.\u0026rdquo; But whatever path lies ahead, I chose it, and I\u0026rsquo;ll see it through even if I have to crawl.\nFinally, a note to myself: as long as your spirit never dies, life will keep running forward.\n\u0026ndash; DevHu, recorded on July 4, 2015, at a rented apartment.\n","date":"2015-07-03T16:55:39Z","permalink":"https://blog.coinidea.com/en/p/written-on-the-zeroth-anniversary-of-graduation/","title":"Written on the Zeroth Anniversary of Graduation"},{"content":"A major life transition is coming - graduation. There\u0026rsquo;s a computer in the lab that\u0026rsquo;s been mine to use, and I wanted to give it a thorough clean before I leave. I heard about a tool called CCleaner, tried it out, and it works quite well. It can conveniently clean up Windows | Mac | Android | iPhone devices.\nOn Windows, you can perform:\nWindows and application cleanup\nRegistry cleanup\nSoftware uninstallation and disk wiping\n","date":"2015-06-21T07:33:06Z","permalink":"https://blog.coinidea.com/en/p/cleaning-your-computer-with-ccleaner/","title":"Cleaning Your Computer with CCleaner"},{"content":"This trip was our graduation trip. After some bumpy arguments and planning (I was worried about MERS; and since my second year of grad school I haven\u0026rsquo;t been a fan of flying, with the flight distance being over ten thousand kilometers), we finally decided on Yunnan.\nTransportation We chose the route Beijing - Kunming - Dali - Kunming - Beijing. Since I basically only fly with Air China, and Air China doesn\u0026rsquo;t have direct flights to Dali\u0026rsquo;s Huangcao Airport, we had to make a transfer, which was quite inconvenient. My suggestion: try to book direct round-trip flights whenever possible.\nIf you\u0026rsquo;re traveling from Kunming, there are two options: bus or train. We took the bus both ways. The fare was around 136 yuan, about 5 hours (Dali Xingsheng Bus Station to Kunming West Bus Station). Unfortunately, we hit a 2-hour traffic jam on the way there. The train takes 7-8 hours. Some people recommend taking the overnight train. Once you arrive in Dali, you can take public buses, which are very cheap at around 1.5 or 2 yuan, from Xiaguan to the Old Town. If it\u0026rsquo;s too late, you can ask the inn to pick you up.\nAccommodation If you have the budget, you could stay in Shuanglang, but we checked and it wasn\u0026rsquo;t very convenient. My suggestion is to stay in the Old Town, which is quite affordable, generally 80-130 yuan per night. We stayed at Mengxingu Inn. It was quite nice - they had a dog, really cute. I was scared at first, but later found it to be very gentle.\nOn the last night, we stayed at 1969 Seaside Inn. It was quite expensive, had no TV, and the water pressure was low. But the environment was absolutely stunning.\nSightseeing You can stroll around the Old Town - it\u0026rsquo;s very relaxing.\nYou can ride bikes along Erhai West Road.\nFinally, a few words of reflection: happy graduation. The road ahead is long - take it one step at a time.\n","date":"2015-06-20T10:41:51Z","permalink":"https://blog.coinidea.com/en/p/travel-guide-yunnan/","title":"Travel Guide - Yunnan"},{"content":"Basic configuration:\nIn Yii\u0026rsquo;s main.php:\n1 2 3 4 5 6 7 8 9 10 11 12 13 return array( ... \u0026#39;components\u0026#39;=\u0026gt;array( \u0026#39;redis_cache\u0026#39; =\u0026gt; array ( \u0026#39;class\u0026#39; =\u0026gt; \u0026#39;system.caching.CRedisCache\u0026#39;, \u0026#39;hostname\u0026#39; =\u0026gt;\u0026#39;127.0.0.1\u0026#39;, \u0026#39;port\u0026#39; =\u0026gt; 6379, \u0026#39;password\u0026#39;=\u0026gt;\u0026#39;123456\u0026#39;, \u0026#39;database\u0026#39;=\u0026gt;1 ), ), ... ) Notes:\nThe CRedisCache in the class field is the official Redis plugin;\nThe password field is required if a password has been set;\nThe database field specifies the corresponding database.\nUsage:\n$r_key = \u0026ldquo;key\u0026rdquo;;\nYii::app()-\u0026gt;redis_cache-\u0026gt;set($r_key, 99999);\necho Yii::app()-\u0026gt;redis_cache-\u0026gt;get($r_key);\nHowever, you won\u0026rsquo;t find a key named \u0026ldquo;key\u0026rdquo; in the Redis database, because Yii\u0026rsquo;s Redis plugin applies MD5 hashing to keys by default.\nBy examining CCache, the parent class of CRedisCache, you\u0026rsquo;ll find that you need to declare the following two variables in CRedisCache.php:\n1 2 public $hashKey = false; public $keyPrefix = \u0026#34;\u0026#34;; This solves the problem.\nAdditionally, if you encounter garbled Chinese characters, it\u0026rsquo;s because Redis defaults to ANSI encoding. When connecting, use the following command:\n./redis-cli \u0026ndash;raw -h 127.0.0.1\nto connect.\nFor official documentation, see: http://www.yiiframework.com/doc/api/1.1/CRedisCache/.\n","date":"2015-06-12T06:24:58Z","permalink":"https://blog.coinidea.com/en/p/redis-configuring-redis-in-yii-common-issues/","title":"[Redis] Configuring Redis in Yii - Common Issues"},{"content":"Sharing a simple online QR code generator I wrote. Click the link below:\nOnline QR Code Generator ","date":"2015-05-30T03:19:13Z","permalink":"https://blog.coinidea.com/en/p/online-qr-code-generator/","title":"Online QR Code Generator"},{"content":"Differences and Connections Between DIV and Table Page Layouts There is currently a debate over whether to use traditional Table or the newer DIV for web page design. Some say Table is better \u0026ndash; faster to develop, easier to control, and better browser compatibility. Others believe DIV is better and represents the future trend, mainly for the following reasons:\nDIV+CSS layouts save page code compared to Table layouts, and the code structure is cleaner and more readable. DIV+CSS development is faster than Table with more precise layouts, though hand-written code increases noticeably. DIV+CSS layouts make website layout modifications simpler. DIV+CSS layouts can adapt to future multi-client requirements. DIV+CSS layouts save site storage space and bandwidth. These are all advantages of DIV. With so many benefits of DIV, you might be tempted to learn it. DIV and Table each have their strengths, and in most cases they can be used interchangeably. I believe the correct standards-compliant design philosophy is: use DIV and other layout elements to create page design layouts, positioning, color blocks, images, etc. Use Table, UL, and similar elements to display data on the page. Because DIV does not behave like Table in IE, where the entire Table must be downloaded before any content is displayed (Firefox does not have this issue), using Table for layout is clearly not ideal, especially with large amounts of data \u0026ndash; it is noticeably slower in IE. DIV handles this much better. Of course, DIV can also serve to organize data.\nDIV for layout, Table for displaying data \u0026ndash; this is the most fundamental design principle today.\nCan a Table contain a DIV? And vice versa, can a DIV contain a Table?\nOf course it can.\nDoes DIV serve the same purpose as Table?\nDIV\u0026rsquo;s functionality is similar to Table, but DIV has better XML support and is more flexible to use, which is why it is recommended as the new approach for web page layout.\nWhich is faster, DIV or Table?\nDIV is relatively faster. Web content display requires downloading a complete block of content before rendering. DIV layout consists of many independent, relatively small blocks, while Table layout typically involves multiple layers of nested tables forming larger download blocks.\nAdditionally, the difference between . and # in CSS:\n. is called using class # is called using id ","date":"2015-05-23T05:38:17Z","permalink":"https://blog.coinidea.com/en/p/html-differences-and-connections-between-div-and-table-page-layouts/","title":"[HTML] Differences and Connections Between DIV and Table Page Layouts"},{"content":" Whether the forum has invitation code registration enabled\nGo to Admin Panel =\u0026gt; Global =\u0026gt; Registration \u0026amp; Access =\u0026gt; Registration. Configure whether to enable invitation-based registration, the extended credits used for invitation rewards, the credit amounts for both the inviter and invitee, and whether successful invitation registrations automatically add each other as friends.\nEdit administrator permissions\nUsers =\u0026gt; User Groups =\u0026gt; Others =\u0026gt; Registration related\nPurchase invitation codes and view them on the friends page\n","date":"2015-05-23T05:37:16Z","permalink":"https://blog.coinidea.com/en/p/discuz-forum-invitation-codes/","title":"[Discuz] Forum Invitation Codes"},{"content":"Starting Nginx 1 /usr/nginx/sbin/nginx 1 /usr/nginx/sbin/nginx -t Check whether the configuration is correct.\nStopping Nginx Stopping is done by sending signals to the nginx process (for more about signals, refer to Linux documentation).\nStep 1: Find the nginx master process ID 1 ps -ef | grep nginx Find the master process in the process list \u0026ndash; its number is the master process ID.\nStep 2: Send a signal Graceful shutdown:\n1 kill -QUIT master_process_id Fast shutdown:\n1 kill -TERM master_process_id Forced shutdown:\n1 pkill -9 nginx Additionally, if the pid file path is configured in nginx.conf, that file contains the Nginx master process ID. If not specified, it is stored in nginx\u0026rsquo;s logs directory. With the pid file, you don\u0026rsquo;t need to look up the master process ID first and can send signals to Nginx directly:\n1 kill -signal_type \u0026#39;/usr/nginx/logs/nginx.pid\u0026#39; Graceful Restart If you changed the configuration, do you need to stop Nginx and start it again? No \u0026ndash; you can send a signal to Nginx for a graceful restart.\nGraceful restart command:\n1 kill -HUP master_process_id_or_pid_file_path Or use:\n1 /usr/nginx/sbin/nginx -s reload Note: After modifying the configuration file, it\u0026rsquo;s best to check whether the modified configuration is correct first, to avoid errors after restart that could affect server stability. The command to check Nginx configuration:\n1 nginx -t -c /usr/nginx/conf/nginx.conf Or:\n1 /usr/nginx/sbin/nginx -t ","date":"2015-05-23T05:36:29Z","permalink":"https://blog.coinidea.com/en/p/nginx-starting-stopping-and-restarting-nginx-on-linux/","title":"[nginx] Starting, Stopping, and Restarting Nginx on Linux"},{"content":"In JavaScript, you can use the window.location.href property to get the full URL. This means we can pass parameters using GET mode, i.e., the form\u0026rsquo;s method=\u0026quot;GET\u0026quot;.\nBelow is a JavaScript function that retrieves values submitted via GET mode.\n1 2 3 4 5 6 7 8 9 10 11 12 function Request(strName) { var strHref = window.document.location.href; var intPos = strHref.indexOf(\u0026#34;?\u0026#34;); var strRight = strHref.substr(intPos + 1); var arrTmp = strRight.split(\u0026#34;\u0026amp;\u0026#34;); for (var i = 0; i \u0026lt; arrTmp.length; i++) { var arrTemp = arrTmp[i].split(\u0026#34;=\u0026#34;); if (arrTemp[0].toUpperCase() == strName.toUpperCase()) return arrTemp[1]; } return \u0026#34;\u0026#34;; } Usage:\nvar id=Request(\u0026quot;id\u0026quot;);\ndocument.write(id);\n","date":"2015-05-23T05:35:22Z","permalink":"https://blog.coinidea.com/en/p/html-passing-values-in-html/","title":"[HTML] Passing Values in HTML"},{"content":" First, modify the hosts file located at C:\\WINDOWS\\system32\\drivers\\etc. Open it with Notepad and add:\n1 2 127.0.0.1 www.a.com 127.0.0.1 www.b.com Open the file xampp\\apache\\conf\\httpd.conf, search for \u0026ldquo;Include conf/extra/httpd-vhosts.conf\u0026rdquo;, and make sure there is no # comment symbol in front of it \u0026ndash; this ensures the vhosts virtual host configuration file is included.\nOnce httpd-vhosts.conf is enabled, the default httpd.conf configuration becomes inactive (make sure virtual host configuration is also enabled in httpd-vhosts.conf, see step 3). All domain requests to this IP will be directed to the first virtual host in vhosts.conf.\nIn the virtual host configuration file xampp\\apache\\conf\\extra\\httpd-vhosts.conf:\nRemove the ## before NameVirtualHost *:80 to enable vhosts.conf. The default httpd.conf configuration becomes inactive, and virtual host settings will only be configured in httpd-vhosts.conf.\n1 2 DocumentRoot /xampp/htdocs/a ServerName www.a.com 1 2 DocumentRoot /xampp/htdocs/b ServerName www.b.com After completing step 3, you will notice that accessing localhost redirects to the path configured for site a. This is explained in step 2 \u0026ndash; once vhosts is enabled, the default httpd configuration becomes inactive, and the default access points to the first entry in vhosts. To fix this, you need to add the localhost directory configuration back.\n1 2 DocumentRoot /xampp/htdocs/ ServerName localhost With this, the XAMPP virtual host setup is complete. Now accessing localhost still shows the original XAMPP welcome page, accessing www.a.com points to the bound directory a, and accessing www.b.com points to the bound directory b.\n","date":"2015-05-23T05:34:23Z","permalink":"https://blog.coinidea.com/en/p/apache-virtual-host-configuration-for-multi-domain-access-to-local-php-projects/","title":"[Apache] Virtual Host Configuration for Multi-Domain Access to Local PHP Projects"},{"content":"Setting Up on Windows XP: Start \u0026ndash; Control Panel \u0026ndash; Administrative Tools \u0026ndash; Services \u0026ndash; Start four key services (Workstation, Telephony, Remote Access Connection Manager, Routing and Remote Access) and set them to start automatically \u0026ndash; Control Panel \u0026ndash; Network Connections \u0026ndash; Incoming Connections \u0026ndash; General tab (check: Virtual Private Network, allow others to establish a private connection to my computer via the Internet or other networks through \u0026ldquo;tunneling\u0026rdquo;) \u0026ndash; Users tab (check which users can connect remotely via VPN) \u0026ndash; Network tab (TCP/IP address assignment: manually specify an IP address in a different subnet from the server, e.g., if the server IP is in the 192.168.1.x range, enter an address in the 192.168.2.x range here).\nFinding the server\u0026rsquo;s external IP address:\nDirect dial-up \u0026ndash; Start \u0026ndash; Control Panel \u0026ndash; Network Connections \u0026ndash; Local Area Connection \u0026ndash; Support \u0026ndash; IP Address: something like \u0026ldquo;58.60._.133\u0026rdquo;. Router dial-up \u0026ndash; Enter the router\u0026rsquo;s IP address (local network gateway) in IE browser \u0026ndash; Find the router\u0026rsquo;s IP address: something like \u0026ldquo;58.60._.133\u0026rdquo;. Windows XP Client Connection Setup: Start \u0026ndash; Control Panel \u0026ndash; Network Connections \u0026ndash; Create a new network connection \u0026ndash; Next \u0026ndash; Connect to the network at my workplace \u0026ndash; Virtual Private Network connection (V) \u0026ndash; Give it a name: VPN \u0026ndash; Do not dial the initial connection \u0026ndash; Enter the server\u0026rsquo;s IP address or domain name, IP address like \u0026ldquo;58.60.*.133\u0026rdquo; \u0026ndash; Finish.\nClient Connection: Start \u0026ndash; Control Panel \u0026ndash; Network Connections \u0026ndash; Under Virtual Private Network you can see the VPN dial-up you just set up \u0026ndash; Double-click to connect.\nOnce connected, your machine will be on the same local network as the server.\nCommon VPN Dial-up Errors: VPN 800 error: The server\u0026rsquo;s external IP address is incorrect or DMZ is not configured. VPN 628 error or VPN 721 error: The client and server\u0026rsquo;s external WAN port are the same. The two computers are on the same LAN under the same ADSL connection. In this case, you can enter the server\u0026rsquo;s (target host\u0026rsquo;s) internal IP address to test the connection. VPN 733 error: TCP/IP CP reported an error. The server and client\u0026rsquo;s incoming IP addresses are in the same subnet. Set the server to manual assignment (Control Panel \u0026ndash; Network Connections \u0026ndash; Incoming Connections \u0026ndash; Network tab \u0026ndash; TCP/IP address assignment: manually specify an IP address in a different subnet from the server, e.g., if the server IP is in the 192.168.1.x range, enter an address in the 192.168.2.x range here). Someone in the lab was around yesterday, and I tried it today \u0026ndash; it works like a charm.\n","date":"2015-05-23T05:33:34Z","permalink":"https://blog.coinidea.com/en/p/vpn-configuration-guide/","title":"[VPN] Configuration Guide"},{"content":"To embed a map in your own web page, the common methods can be summarized as follows:\nThe Simplest Method \u0026ndash; Using Google Maps\u0026rsquo; \u0026ldquo;Link\u0026rdquo; Feature\nIf you only need to display a specific area on your page, such as your company\u0026rsquo;s location, without adding any extra content like markers or polylines, this is the easiest way to embed Google Maps.\nGo to the Google Maps homepage, navigate to the area you want to display, then click \u0026ldquo;Link\u0026rdquo; in the upper left corner of the map. An info box will appear with two input fields \u0026ndash; copy the content from the second input field into your page and you\u0026rsquo;re done.\nThis embed code is essentially an iframe declaration. Although the Maps homepage provides a customization and preview feature, it only allows you to customize the map size. If needed, you can manually modify the iframe declaration for further customization, such as adding custom styles to the iframe.\nThe Most Lightweight Method \u0026ndash; Using Google Static Maps\nIf you need to display a specific area and add some markers or polylines, but don\u0026rsquo;t care whether the map on your page is draggable, then static maps are what you need.\nA static map means what you embed in your page is actually just a GIF image, dynamically fetched from Google via a URL. This differs from the \u0026ldquo;dynamic\u0026rdquo; maps we commonly use, and loading such a map is much faster than loading a full interactive map.\nTo use a static map on your page, simply use an img tag and set its src attribute to the Google Static Maps URL.\nHere\u0026rsquo;s a simple static map URL:\n1 http://ditu.google.cn/staticmap?center=39.970981,116.314108\u0026amp;zoom=16\u0026amp;size=400×400\u0026amp;key=YOUR_API_KEY In this URL, you can edit parameters like center, zoom, and size to specify the map\u0026rsquo;s center point, zoom level, map dimensions, and more. Of course, you can also add parameters for markers and polylines. Don\u0026rsquo;t worry about memorizing all these parameters \u0026ndash; there\u0026rsquo;s a static map customization wizard that guides you through a few simple steps to get the URL you need. If interested, you can explore the Google Static Maps API documentation.\nStrictly speaking, Google Static Maps is also a type of Google Maps API, so using static maps requires your Google Maps API key. If you\u0026rsquo;ve already registered a Maps API key, you can simply reuse it.\nThe Most Flexible Method \u0026ndash; Using the Google Maps API\nIf neither of the above methods meets your needs, try the Google Maps API. Although the Google Maps API has been divided into JavaScript, Flash, Earth, Static, and other versions, in my view, the JavaScript API is the foundation of the Google Maps API. So unless otherwise specified, \u0026ldquo;Google Maps API\u0026rdquo; here refers to the Google Maps JavaScript API. With this API, you can display your data on the map in any feasible way you like, and you can even make your own map look better than Google Maps itself.\nTo embed a map in your page using this API, the basic steps are:\nImport the Maps API library using a JavaScript tag; Define an element on the page to hold the map, typically a div tag with specified width and height; In your JavaScript code: new GMap2(document.getElementById(\u0026quot;your map container's id\u0026quot;)); Use classes provided by the API such as GMarker, GPolyline, etc. to customize the markers, polylines, and other elements on the map. For a detailed guide on creating Google Maps, see the \u0026ldquo;Creating Maps with JavaScript Guide\u0026rdquo; above. However, to use this API proficiently, you need a certain level of JavaScript knowledge and hands-on ability. Additionally, it\u0026rsquo;s strongly recommended to read the Google Maps JavaScript API Developer Guide first, which can answer many common questions. Of course, you can also find the information you\u0026rsquo;re looking for in this documentation.\nBeyond the methods described above, there are some less commonly used ways to embed maps in web pages, which won\u0026rsquo;t be covered here.\n","date":"2015-05-23T05:32:44Z","permalink":"https://blog.coinidea.com/en/p/mapservice-how-to-embed-maps-in-your-own-web-pages/","title":"[MapService] How to Embed Maps in Your Own Web Pages"},{"content":"Page A has a form.\nYou submit this page and are redirected to page B.\nOn page B, pressing the refresh key will trigger a dialog asking to resend the form data.\nThis problem can be solved from the web development perspective.\nPage A submits to your server page (ASP, JSP).\nThe server page processes the request but does not return page B to the user directly.\nInstead, it returns a simple page C, such as a redirect page.\nThis immediately redirects to page B \u0026ndash; in this case, main.jsp.\nIf you refresh on page B, the resend dialog will not appear.\nIf you press \u0026ldquo;Back\u0026rdquo; on page B, you will go back to page A.\nThe user will not notice the intermediate page C at all.\nGoing further, you can design a JavaScript dialog box that, once confirmed, will not pop up again regardless of whether the user refreshes or navigates back.\nredirect.jsp\n","date":"2015-05-23T05:30:50Z","permalink":"https://blog.coinidea.com/en/p/html-preventing-duplicate-form-submission-on-f5-refresh/","title":"[HTML] Preventing Duplicate Form Submission on F5 Refresh"},{"content":"When a JSP website is ready to be published, it can be a headache for individuals or students without a budget.\nI encountered this problem too. After searching online, I found two helpful blog posts:\nRecommending a free JSP hosting service: http://fireinwind.iteye.com/blog/705611\nThis blog post introduced me to two free JSP hosting options: jhost and EATJ.\nHere are my thoughts on using these two free hosting services \u0026ndash; free services inevitably have drawbacks. For example, jhost is extremely slow to access from the campus network, and uploading files takes forever. EATJ\u0026rsquo;s drawback is that it shuts down your server every six hours each day, and you have to restart it manually (shutdown times are 4:00, 10:00, 14:00, 18:00, and 24:00).\nSo I recommend using EATJ when you don\u0026rsquo;t have a budget in the early stages. The speed is decent and it works well enough \u0026ndash; the only downside is having to restart the server. It is perfectly suitable for testing purposes.\nAs for jhost, it has a better user experience, designed with a desktop OS-style interface for easier management, but it is slow.\nFor detailed instructions on how to use these two hosting services, see the blog post:\njsp php enthusiasts\u0026rsquo; good news: eatj and jhost\nNote: Applying for jhost is somewhat complicated and requires an invitation code. You can search for \u0026ldquo;jhost invitation code\u0026rdquo; online.\nAfter activating your account, log in to the hosting backend and activate your Website Hosting Service in the Control Panel.\nSite policy: Regular users must log in and renew at least once every 3 days (click the Renew button in the Member Service Management section of the Control Panel) to confirm you are still using the service.\nAdditionally, the site periodically suspends the TOMCAT service for users who have not renewed within the specified time. The next renewal will restart the service. If you do not renew for over a month, your account will be deactivated.\nYou can extend your hosting usage period or redeem other services through site credits. Credits can be earned by referring users or purchased with cash. See the site\u0026rsquo;s help section for details.\n","date":"2015-05-23T05:29:00Z","permalink":"https://blog.coinidea.com/en/p/jsp-free-jsp-hosting/","title":"[JSP] Free JSP Hosting"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 int Fibonacci(int n) { if (1 == n) { return 1; } if (2 == n) { return 2; } return Fibonacci(n-1) + Fibonacci(n-2); } int FibonacciIteration (int n) { int a = 1; int b = 2; if (n == 1) return a; if (n == 2) return b; for (int i = 3; i \u0026lt;= n; i++) { int now = a + b; a = b; b = now; } return b; } The book mentions a method: fi = fi-1 + fi-2 =\u0026gt; converted into matrix form\n[Beauty of Programming 2.9] Fibonacci Sequence\nTime complexity: O(log2n).\n","date":"2015-05-23T05:20:58Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.9-fibonacci-sequence/","title":"[Beauty of Programming 2.9] Fibonacci Sequence"},{"content":"The problem is simple: given an integer n, find the smallest m such that n*m contains only the digits 0 and 1 in its decimal representation.\nMethod 1: Brute Force [Need to consider large integers, termination conditions, and time complexity]\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 bool CheckNumber(int number) { while(number) { if (number%10 != 0 \u0026amp;\u0026amp; number%10 != 1) return false; number /= 10; } return true; } int CalcMBruteForce(int n) { int m = 1; while (!CheckNumber(m * n)) { m++; } return m; } Method 2: BFS [Need to consider large integers, termination conditions, and duplicate elimination]\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 int CalcM(int number) { int i = 1; vector\u0026lt;int\u0026gt; vList; vList.clear(); vList.push_back(0); vList.push_back(1); vector\u0026lt;int\u0026gt; vListC; int k = 1; // TODO: // BigInt // Delete duplicate while (true) { vListC.clear(); for (vector\u0026lt;int\u0026gt;::size_type i = 0; i \u0026lt; vList.size(); i++) { if (vList[i] \u0026amp;\u0026amp; vList[i] % number == 0) { return vList[i]; } vListC.push_back(vList[i] + 0); vListC.push_back(vList[i] + (int)pow(10.0, k)); } vList.clear(); vList = vListC; k++; } } ","date":"2015-05-23T05:19:47Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.8-finding-integers-that-meet-the-criteria/","title":"[Beauty of Programming 2.8] Finding Integers That Meet the Criteria"},{"content":"GCD: Greatest Common Divisor \u0026ndash; the largest integer that divides both m and n evenly.\nEuclid\u0026rsquo;s algorithm (the Euclidean algorithm) has existed since ancient times:\nGCD(x, y) = GCD(x, x%y)\nx = k*y + b. If d is the GCD of x and y, then d must also divide b, and d is the GCD of x and b, where b = x%y.\nCode:\n1 2 3 4 5 // GCD int GCD(int x, int y) { return y == 0 ? x : GCD(y, x % y); } The book \u0026ldquo;Beauty of Programming\u0026rdquo; discusses time optimizations:\nThe modulo operation involves division, which is relatively expensive. How to optimize for big integers. ","date":"2015-05-23T05:18:46Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.7-the-greatest-common-divisor-problem/","title":"[Beauty of Programming 2.7] The Greatest Common Divisor Problem"},{"content":"The code below simplifies the problem to converting a repeating decimal into a fraction. For terminating decimals, you can convert them directly to fractions, but this involves another important concept: finding the greatest common divisor (GCD). The classic method is the Euclidean algorithm.\nCode:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // GCD int GCD(int x, int y) { return y == 0 ? x : GCD(y, x % y); } // Simplified conditions // x: repeating decimal // n: integer representation of the repeating block // m: length of the repeating block // 10^m * x = n + x // x = n / (10^m - 1) void FloatNumber(string number) { int start = number.find_first_of(\u0026#39;(\u0026#39;) + 1; int end = number.find_first_of(\u0026#39;)\u0026#39;); string repetend = number.substr(start, end - start); int n = atoi(repetend.c_str()); int m = end - start; int d = GCD(n, ((int)pow(10.0, m) - 1)); cout \u0026lt;\u0026lt; n / d \u0026lt;\u0026lt; \u0026#39;/\u0026#39; \u0026lt;\u0026lt; ((int)pow(10.0, m) - 1) / d \u0026lt;\u0026lt; endl; } ","date":"2015-05-23T05:17:49Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.6-exact-representation-of-floating-point-numbers/","title":"[Beauty of Programming 2.6] Exact Representation of Floating Point Numbers"},{"content":"This problem is equivalent to finding the k-th largest/smallest number.\nMethod 1: Sort and output directly. [The book \u0026ldquo;Beauty of Programming\u0026rdquo; notes that different sorting methods have different time complexities. Indeed, since we don\u0026rsquo;t need all n numbers sorted \u0026ndash; we only need the k largest.]\nUsing quicksort:\n1 2 3 4 5 6 vector\u0026lt;int\u0026gt; FindMostKSort(vector\u0026lt;int\u0026gt;\u0026amp; vNumbers, int k) { sort(vNumbers.begin(),vNumbers.end()); vector\u0026lt;int\u0026gt; vKNumbers(vNumbers.rbegin(), vNumbers.rbegin() + k); return vKNumbers; } Method 2: We don\u0026rsquo;t actually need all numbers sorted. We can simulate the partition step of quicksort to find the element at the k-th position after sorting.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 void swap(int \u0026amp;a, int \u0026amp;b) { int tmp = a; a = b; b = tmp; } void FindMostKPartition(vector\u0026lt;int\u0026gt;\u0026amp; vNumber, int k, int left, int right) { int index = left; int tmp = vNumber[index]; int i = left; int j = right; while (i \u0026lt; j) { while(i \u0026lt; j \u0026amp;\u0026amp; vNumber[j] \u0026gt;= vNumber[index]) j--; swap(vNumber[j], vNumber[index]); index = j; while(i \u0026lt; j \u0026amp;\u0026amp; vNumber[i] \u0026lt;= vNumber[index]) i++; swap(vNumber[i], vNumber[index]); index = i; } if (index - left + 1 == k) { cout \u0026lt;\u0026lt; vNumber[index] \u0026lt;\u0026lt; endl; } else if (index - left + 1 \u0026lt; k) { FindMostKPartition(vNumber, k - (index - left + 1), index + 1, right); } else { FindMostKPartition(vNumber, k, left, index - 1); } } Method 3: Heap sort [maintain a min-heap of size k. The STL code is remarkably short, though you could implement the heap with arrays yourself.]\nPS: All sorting uses STL implementations. Implementing sorting from scratch will be attempted in the near future.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 void FindMostKHeap(vector\u0026lt;int\u0026gt;\u0026amp; vNumbers, int k) { vector\u0026lt;int\u0026gt; vKNumbers(vNumbers.begin(), vNumbers.begin() + k); make_heap(vKNumbers.begin(), vKNumbers.end(), greater\u0026lt;int\u0026gt;()); for (vector\u0026lt;int\u0026gt;::size_type i = k; i \u0026lt; vNumbers.size(); i++) { if (vNumbers[i] \u0026gt; vKNumbers[0]) { vKNumbers[0] = vNumbers[i]; make_heap(vKNumbers.begin(), vKNumbers.end(), greater\u0026lt;int\u0026gt;()); } } cout \u0026lt;\u0026lt; vKNumbers[0] \u0026lt;\u0026lt; endl; } ","date":"2015-05-23T05:16:43Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.5-finding-the-k-largest-numbers/","title":"[Beauty of Programming 2.5] Finding the K Largest Numbers"},{"content":"The problem is straightforward: given a positive integer n, count the total number of times the digit 1 appears in all numbers from 1 to n.\nFor example, for the number 12312, global count += 2 because 1 appears twice. Given input n, we need to compute this for all numbers from 1 to n.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 int VerifyCountOneNumberAns(int n) { int ans = 0; for (int i = 1; i \u0026lt;= n; i++) { int tmp = i; while(tmp) { if (1 == tmp%10) ans++; tmp /= 10; } } return ans; } int CountOneNumber(int n) { if (n == 0) return 0; if (n \u0026lt; 10) return 1; vector\u0026lt;int\u0026gt; vNumber; vNumber.clear(); int tmp = n; while(tmp) { vNumber.push_back(tmp%10); tmp /= 10; } int count = 0; int vSize = vNumber.size(); count = (vSize - 1) * vNumber[vSize - 1] * (int)pow(10.0, (int)(vSize - 2)); if (vNumber[vSize - 1] \u0026gt; 1) { count += (int)pow(10.0, (int)(vSize - 1)); } else { count += n - vNumber[vSize - 1] * (int)pow(10.0, vSize - 1) + 1; } count += CountOneNumber(n - vNumber[vSize - 1] * (int)pow(10.0, vSize - 1)); return count; } int main() { vector\u0026lt;int\u0026gt; ids; for (int i = 1; i \u0026lt;= 10000; i++) { int count = CountOneNumber(i); int ans = VerifyCountOneNumberAns(i); if (ans != count) cout \u0026lt;\u0026lt; i \u0026lt;\u0026lt; \u0026#39;\\t\u0026#39; \u0026lt;\u0026lt; ans \u0026lt;\u0026lt; \u0026#39;\\t\u0026#39; \u0026lt;\u0026lt; count \u0026lt;\u0026lt; endl; } return 0; } The code includes a verification function whose correctness is beyond doubt. The problem also provides a recursive approach, which has acceptable time complexity \u0026ndash; it should be proportional to the number of digits.\nPS: I\u0026rsquo;m clearly not great at math; this was quite a struggle. But my logic still works well\u0026hellip;\n","date":"2015-05-23T05:15:31Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.4-count-of-digit-1/","title":"[Beauty of Programming 2.4] Count of Digit 1"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int FindMostIds(vector\u0026lt;int\u0026gt; \u0026amp;ids) { map\u0026lt;int,int\u0026gt; hashIds; map\u0026lt;int,int\u0026gt;::iterator it; hashIds.clear(); for (int i = 0; i \u0026lt; ids.size(); i++) { it = hashIds.find(ids[i]); if (hashIds.end() == it) { hashIds.insert(map\u0026lt;int,int\u0026gt;::value_type(ids[i],1)); } else { it-\u0026gt;second++; } } int id = 0, count = -1; for (it = hashIds.begin(); it != hashIds.end(); it++) { if (it-\u0026gt;second \u0026gt; count) { id = it-\u0026gt;first; count = it-\u0026gt;second; } } return id; } This problem can be further optimized in two ways: 1) Optimize the solution itself; 2) If there are 3 \u0026ldquo;spammers,\u0026rdquo; each posting more than a quarter of all posts, how do we solve it? It\u0026rsquo;s late today, heading back to the dorm. I\u0026rsquo;ll solve it tomorrow \u0026ndash; though I already have an idea.\nProblem 1:\nThe book \u0026ldquo;Beauty of Programming\u0026rdquo; mentions that space complexity can be optimized to O(1).\nAfter reading the book, here\u0026rsquo;s the hint:\nUse one variable id to store the current ID and count to store the count of that ID, then compare for equality and maintain dynamically. The final id must be the spammer.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 int FindMostIds(vector\u0026lt;int\u0026gt; \u0026amp;ids) { if (ids.size() \u0026lt;= 0) return -1; int id = ids[0]; int count = 1; for (vector\u0026lt;int\u0026gt;::size_type i = 1; i \u0026lt; ids.size(); i++) { if (0 == count) { id = ids[i]; count = 1; continue; } if (id == ids[i]) { count++; } else { count--; } } return id; } Problem 2: This can be generalized from the approach in Problem 1, Solution 2: [my own idea, not rigorously tested, but the logic should be correct]\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 void FindMostIds(vector\u0026lt;int\u0026gt; \u0026amp;ids) { if (ids.size() \u0026lt;= 0) return ; int id[3] = {-1, -1, -1}; int count[3] = {0, 0, 0}; for (vector\u0026lt;int\u0026gt;::size_type i = 1; i \u0026lt; ids.size(); i++) { bool flag = false; for (int j = 0; j \u0026lt; 3; j++) { if (id[j] == ids[i]) { count[j]++; flag = true; break; } } if (flag) continue; flag = false; for (int j = 0; j \u0026lt; 3; j++) { if (count[j] == 0) { id[j] = ids[i]; count[j]++; flag = true; break; } } if (flag) continue; for (int j = 0; j \u0026lt; 3; j++) { count[j]--; } } for (int i = 0; i \u0026lt; 3; i++) { cout \u0026lt;\u0026lt; id[i] \u0026lt;\u0026lt; \u0026#39;\\t\u0026#39;; } cout \u0026lt;\u0026lt; endl; } ","date":"2015-05-23T05:14:27Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.3-finding-the-forum-spammer/","title":"[Beauty of Programming 2.3] Finding the Forum \"Spammer\""},{"content":" The problem asks to count the number of trailing zeros in n!. This is essentially counting how many multiples of 5 are multiplied in during the computation of n!.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 int CountZero(int n) { int cnt = 0; for (int i = 1; i \u0026lt;= n; i++) { int tmp = i; while (0 == i % 5) { cnt++; tmp /= 5; } } return cnt; } The problem asks for the position of the lowest bit 1 in the binary representation of N!. We can observe that multiplying by odd numbers doesn\u0026rsquo;t affect the position of 1. Each time we multiply by 2, the entire value shifts left by 1 bit. Therefore, the result depends on the number of times 2 appears as a factor.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 int CountBinaryOne(int n) { int cnt = 0; for (int i = 1; i \u0026lt;= n; i++) { int tmp = i; while (0 == tmp % 2) { cnt++; tmp /= 2; } } return cnt; } ","date":"2015-05-23T05:11:00Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.2-dont-be-scared-by-factorials/","title":"[Beauty of Programming 2.2] Don't Be Scared by Factorials"},{"content":" 1 2 3 4 5 6 7 8 9 10 int CountOne(int val) { int cnt = 0; while (val) { val \u0026amp;= val - 1; cnt++; } return cnt; } ","date":"2015-05-23T05:09:14Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-2.1-count-the-number-of-1s-in-binary/","title":"[Beauty of Programming 2.1] Count the Number of 1s in Binary"},{"content":"Getting the CPU to run at full load is actually quite simple \u0026ndash; just write an infinite loop and the OS will allocate more and more time slices to it. However, modern processors are multi-core. For example, my computer has 4 cores, so you\u0026rsquo;ll find the CPU stays around 25-27% and never reaches 100%.\nTo reach 100%, you just need to use multithreading.\nThe most provocative statement I saw today was:\n\u0026ldquo;I dare you to make the CPU draw a circle.\u0026rdquo; I was completely stunned at that moment\u0026hellip;\nNow let\u0026rsquo;s look at the 50% case. The book \u0026ldquo;Beauty of Programming\u0026rdquo; says that alternating between \u0026ldquo;sleep for one time slice, work for one time slice\u0026rdquo; should achieve 50%. But I found the results were not great. Even using GetTickCount, the effect was poor because the computer has other programs running as well.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 void Work(DWORD time) { DWORD now = GetTickCount(); for(;GetTickCount() \u0026lt;\u0026lt;- endstream\u0026gt;\u0026gt; now + time;) { } } DWORD WINAPI DrawThread(LPVOID lParam) { double deta = 0.1f; while (true) { double time = 500 + 500 * sin(deta); Work(time); Sleep(1000-time); deta += 0.1f; } return 0; } int main() { HANDLE hThread[4]; DWORD idThread[4]; hThread[0] = CreateThread(0,0,DrawThread,NULL,0,\u0026amp; idThread[0]); hThread[1] = CreateThread(0,0,DrawThread,NULL,0,\u0026amp; idThread[1]); hThread[2] = CreateThread(0,0,DrawThread,NULL,0,\u0026amp; idThread[2]); hThread[3] = CreateThread(0,0,DrawThread,NULL,0,\u0026amp; idThread[3]); SetThreadAffinityMask(hThread[0], 0x00000001); SetThreadAffinityMask(hThread[1], 0x00000010); SetThreadAffinityMask(hThread[2], 0x00000100); SetThreadAffinityMask(hThread[3], 0x00001000); WaitForSingleObject(hThread[0], INFINITE); WaitForSingleObject(hThread[1], INFINITE); WaitForSingleObject(hThread[2], INFINITE); WaitForSingleObject(hThread[3], INFINITE); return 0; } ","date":"2015-05-23T05:06:15Z","permalink":"https://blog.coinidea.com/en/p/beauty-of-programming-1-drawing-curves-with-cpu-usage/","title":"[Beauty of Programming 1] Drawing Curves with CPU Usage"},{"content":" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution { public: int getFirstLetter(string \u0026amp;s,int start) { int i; for(i = start;i \u0026lt; s.length();i++) { if(s[i] != \u0026#39; \u0026#39;)return i; } return i; } int getFirstBlank(string \u0026amp;s,int start) { int i; for(i = start;i \u0026lt; s.length();i++) { if(s[i] == \u0026#39; \u0026#39;)return i; } return i; } void reverseWords(string \u0026amp;s) { vector\u0026lt;string\u0026gt; splits; splits.clear(); int i = 0; while(i \u0026lt; s.length()) { i = getFirstLetter(s,i); if(i \u0026gt;= s.length())break; int next = getFirstBlank(s,i+1); if(next \u0026gt;= s.length()) { next = s.length()-1; splits.push_back(s.substr(i,next-i+1)); break; } splits.push_back(s.substr(i,next-i)); i = next; } s = \u0026#34;\u0026#34;; for(int i = splits.size()-1;i \u0026gt;= 0;i--) { s += splits[i]; if(i != 0)s += \u0026#34; \u0026#34;; } } }; ","date":"2015-05-23T03:22:13Z","permalink":"https://blog.coinidea.com/en/p/leetcode_151reverse-words-in-a-string/","title":"[leetcode_151]Reverse Words in a String"},{"content":"\n","date":"2015-05-23T03:21:17Z","permalink":"https://blog.coinidea.com/en/p/leetcode-a-screenshot-to-commemorate/","title":"[leetcode] A Screenshot to Commemorate"},{"content":"So excited! Finally AC\u0026rsquo;d all LeetCode problems at once! Although the journey had its twists and turns, I\u0026rsquo;m still thrilled!\nThis is a simulation problem \u0026ndash; formatting strings according to specified rules. The great thing about LeetCode is that you can see the test data, understand the problem statement thoroughly, and debug step by step. Getting it AC on the first try is actually quite difficult.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 class Solution { public: vector\u0026lt;string\u0026gt; fullJustify(vector\u0026lt;string\u0026gt; \u0026amp;words, int L) { vector\u0026lt;vector\u0026lt;string\u0026gt;\u0026gt; result; result.clear(); vector\u0026lt;string\u0026gt; ans; ans.clear(); if (L == 0) { ans.push_back(\u0026#34;\u0026#34;); return ans; } for (int i = 0; i \u0026lt; words.size(); i++) { vector\u0026lt;string\u0026gt; item; item.clear(); int sum = 0; while (true) { if (item.size() \u0026gt; 0) sum += 1; if (sum \u0026gt;= L) { i--; break; } if (i \u0026gt;= words.size()) break; item.push_back(words[i]); sum += words[i].length(); if (sum \u0026gt; L) { item.pop_back(); i--; break; } i++; } result.push_back(item); } for (int i = 0; i \u0026lt; result.size(); i++) { string item = \u0026#34;\u0026#34;; if (i != result.size() - 1) item = genString(result[i], L); else item = genStringLast(result[i], L); ans.push_back(item); } return ans; } private: string genStringLast(vector\u0026lt;string\u0026gt; \u0026amp;item, int L) { int sum = 0; string str = \u0026#34;\u0026#34;; for (int i = 0; i \u0026lt; item.size(); i++) { str += item[i]; sum += item[i].size(); if (i != item.size() - 1) { str += \u0026#34; \u0026#34;; sum += 1; } } for (int i = 0; i \u0026lt; L - sum; i++) str += \u0026#34; \u0026#34;; return str; } string genString(vector\u0026lt;string\u0026gt; \u0026amp;item, int L) { int sum = 0; for (int i = 0; i \u0026lt; item.size(); i++) sum += item[i].size(); string str = \u0026#34;\u0026#34;; if (item.size() == 1) { int countS = L - sum; str += item[0]; for (int j = 0; j \u0026lt; countS; j++) str += \u0026#34; \u0026#34;; return str; } int spaces; if (item.size() \u0026gt; 1) spaces = (L - sum) / (item.size() - 1); else spaces = 0; int ex = L - sum - spaces * (item.size() - 1); for (int i = 0; i \u0026lt; item.size(); i++) { str += item[i]; int countS; if (i \u0026lt; ex) countS = 1 + spaces; else countS = spaces; if (i != item.size() - 1) for (int j = 0; j \u0026lt; countS; j++) str += \u0026#34; \u0026#34;; } return str; } }; ","date":"2015-05-23T03:20:29Z","permalink":"https://blog.coinidea.com/en/p/leetcode_68text-justification/","title":"[leetcode_68]Text Justification"},{"content":"Use a doubly linked list to simulate a queue, then two maps to store key-value and key-ListNode for optimized lookup time.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 struct ListNodel { int key; ListNodel *before; ListNodel *next; ListNodel(int x) : key(x), before(NULL), next(NULL) {} }; class LRUCache{ public: map\u0026lt;int, int\u0026gt; mapkv; map\u0026lt;int, ListNodel*\u0026gt; mapkl; int capacityq; ListNodel * head, *tail; LRUCache(int capacity) { capacityq = capacity; mapkv.clear(); mapkl.clear(); head = NULL; tail = NULL; } int get(int key) { map\u0026lt;int, int\u0026gt;::iterator it = mapkv.find(key); if (it != mapkv.end()) { update(key); return it-\u0026gt;second; } else { return -1; } } void set(int key, int value) { map\u0026lt;int, int\u0026gt;::iterator it = mapkv.find(key); if (it != mapkv.end()) { it-\u0026gt;second = value; update(key); } else { if (mapkv.size() \u0026lt; capacityq) { insertKeyValue(key, value); } else { ListNodel * tmp = head; head = head-\u0026gt;next; mapkl.erase(tmp-\u0026gt;key); mapkv.erase(tmp-\u0026gt;key); delete(tmp); insertKeyValue(key, value); } } } private: void insertKeyValue(int key, int value) { mapkv.insert(map\u0026lt;int, int\u0026gt;::value_type(key, value)); if (head == NULL) { ListNodel * tmp = new ListNodel(key); mapkl.insert(map\u0026lt;int, ListNodel*\u0026gt;::value_type(key, tmp)); head = tmp; tail = tmp; head-\u0026gt;next = tail; tail-\u0026gt;before = head; tail-\u0026gt;next = NULL; } else { ListNodel * tmp = new ListNodel(key); mapkl.insert(map\u0026lt;int, ListNodel*\u0026gt;::value_type(key, tmp)); tmp-\u0026gt;before = tail; tail-\u0026gt;next = tmp; tmp-\u0026gt;next = NULL; tail = tmp; } } void update(int key) { map\u0026lt;int, ListNodel*\u0026gt;::iterator it = mapkl.find(key); ListNodel * tmp = it-\u0026gt;second; if (tmp == head) { if (head-\u0026gt;next != NULL) { head = head-\u0026gt;next; tail-\u0026gt;next = tmp; tmp-\u0026gt;before = tail; tmp-\u0026gt;next = NULL; tail = tmp; } } else if (tmp != tail) { ListNodel * tmpb = tmp-\u0026gt;before; ListNodel * tmpn = tmp-\u0026gt;next; tmpb-\u0026gt;next = tmpn; tmpn-\u0026gt;before = tmpb; tmp-\u0026gt;before = tail; tail-\u0026gt;next = tmp; tmp-\u0026gt;next = NULL; tail = tmp; } } }; ","date":"2015-05-23T03:19:36Z","permalink":"https://blog.coinidea.com/en/p/leetcode_146lru-cache/","title":"[leetcode_146]LRU Cache"},{"content":"DFS kept timing out, even with memoization. Here is the code for the record:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Solution { public: bool isMatch(const char *s, const char *p) { // Note: The Solution object is instantiated only once and is reused by each test case. const char *tmp = p; int cnt = 0; while (*tmp != \u0026#39;\\0\u0026#39;) if (*(tmp++) != \u0026#39;*\u0026#39;) cnt++; if (cnt \u0026gt; strlen(s)) return false; if(strlen(s) == 0) { for(int i = 0;i \u0026lt; strlen(p);i++) { if(p[i] != \u0026#39;*\u0026#39;)return false; } return true; } int **dp; dp = new int*[strlen(s) + 1]; for(int i = 0; i \u0026lt;= strlen(s); i++) { dp[i] = new int[strlen(p) + 1]; } dp[0][0] = 1; int i = 0; while(p[i++] == \u0026#39;*\u0026#39;) dp[0][i] = 1; for(int i = 1; i \u0026lt;= strlen(s); i++) { for(int j = 1; j \u0026lt;= strlen(p); j++) { if(dp[i-1][j-1] == 1 \u0026amp;\u0026amp; (s[i-1] == p[j-1] || p[j-1] == \u0026#39;?\u0026#39;)) { dp[i][j] = 1; } if(p[j-1] == \u0026#39;*\u0026#39; \u0026amp;\u0026amp; (dp[i][j-1] == 1 || dp[i-1][j-1] == 1 || dp[i-1][j] == 1)) { dp[i][j] = 1; } } } if(dp[strlen(s)][strlen(p)] == 1) return true; else return false; } }; ","date":"2015-05-23T03:18:44Z","permalink":"https://blog.coinidea.com/en/p/leetcode_44wildcard-matching/","title":"[leetcode_44]Wildcard Matching"},{"content":"Another BFS problem. Start from the boundary to find \u0026lsquo;O\u0026rsquo;s; any \u0026lsquo;O\u0026rsquo; not visited is surrounded by \u0026lsquo;X\u0026rsquo;.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 struct Pointp { int x; int y; Pointp() : x(0), y(0) {} Pointp(int a, int b) : x(a), y(b) {} }; class Solution { public: int lenm,lenn; int **map; void solve(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board) { lenm = board.size(); if(lenm \u0026lt;= 1)return ; lenn = board[0].size(); map = new int *[lenm]; for(int i = 0;i \u0026lt; lenm;i++) { map[i] = new int[lenn]; } for(int i = 0;i \u0026lt; lenm;i++) { for(int j = 0;j \u0026lt; lenn;j++) { if(board[i][j] == \u0026#39;O\u0026#39;)map[i][j] = 0; else if(board[i][j] == \u0026#39;X\u0026#39;)map[i][j] = 1; } } for(int i = 0;i \u0026lt; lenm;i++) { for(int j = 0;j \u0026lt; lenn;j++) { if((i == 0 || j == 0 || i == lenm-1 || j == lenn-1)\u0026amp;\u0026amp;(map[i][j] == 0)) { map[i][j] = 2; bfs(i,j); } } } for(int i = 0;i \u0026lt; lenm;i++) { for(int j = 0;j \u0026lt; lenn;j++) { if(map[i][j] != 2)board[i][j] = \u0026#39;X\u0026#39;; } } //for(int i = 0;i \u0026lt; lenm;i++) { // for(int j = 0;j \u0026lt; lenn;j++) { // cout \u0026lt;\u0026lt; board[i][j] \u0026lt;\u0026lt; \u0026#39; \u0026#39;; // } // cout \u0026lt;\u0026lt; endl; //} } private: void bfs(int x,int y) { int walk[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; vector\u0026lt;Pointp\u0026gt;arr,arrs; arr.clear(); arrs.clear(); Pointp p(x,y); arr.push_back(p); while(true) { arrs.clear(); for(int i = 0;i \u0026lt; arr.size();i++) { for(int j = 0;j \u0026lt; 4;j++) { int x = arr[i].x + walk[j][0]; int y = arr[i].y + walk[j][1]; if((x \u0026gt;= 0 \u0026amp;\u0026amp; x \u0026lt;= lenm-1)\u0026amp;\u0026amp;(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt;= lenn-1)\u0026amp;\u0026amp;map[x][y] == 0) { map[x][y] = 2; arrs.push_back(Pointp(x,y)); } } } if(arrs.size() == 0)break; arr.clear(); for(int i = 0;i \u0026lt; arrs.size();i++) { arr.push_back(arrs[i]); } } } }; ","date":"2015-05-23T03:17:52Z","permalink":"https://blog.coinidea.com/en/p/leetcode_130surrounded-regions/","title":"[leetcode_130]Surrounded Regions"},{"content":"Again using BFS. This problem requires a DP check to determine whether a solution exists. I also learned this from reading others\u0026rsquo; blogs; otherwise it would keep getting TLE.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 class Solution { public: bool **map; set\u0026lt;int\u0026gt; wordlens; vector\u0026lt;string\u0026gt; result; vector\u0026lt;string\u0026gt; wordBreak(string s, unordered_set\u0026lt;string\u0026gt; \u0026amp;dict) { wordlens.clear(); unordered_set\u0026lt;string\u0026gt;::iterator it; for(it = dict.begin(); it != dict.end(); it++) { string itstr = *it; wordlens.insert(itstr.length()); } result.clear(); map = new bool*[s.length()]; for(int i = 0; i \u0026lt; s.length(); i++) { map[i] = new bool[s.length()]; for(int j = 0; j \u0026lt; s.length(); j++) { map[i][j] = false; } } for(int start = 0; start \u0026lt; s.length(); start++) { for(int len = 1; len \u0026lt;= s.length() - start; len++) { string tmp = s.substr(start, len); if(dict.find(tmp) != dict.end()) { map[start][start + len - 1] = true; } } } for(int i = 0; i \u0026lt; s.length(); i++) { for(int j = 0; j \u0026lt;= i; j++) { for(int k = j; k \u0026lt; i; k++) { if(map[j][k] \u0026amp;\u0026amp; map[k + 1][i]) map[j][i] = true; } } } // for(int i = 0; i \u0026lt; s.length(); i++) { // for(int j = 0; j \u0026lt; s.length(); j++) { // cout \u0026lt;\u0026lt; map[i][j] \u0026lt;\u0026lt; \u0026#39; \u0026#39;; // } // cout \u0026lt;\u0026lt; endl; // } if(map[0][s.length() - 1] == false) return result; string item = \u0026#34;\u0026#34;; findSen(s, 0, dict, item); return result; } private: void findSen(string \u0026amp;s, int start, unordered_set\u0026lt;string\u0026gt; \u0026amp;dict, string \u0026amp;item) { if(start \u0026gt;= s.length()) { result.push_back(item); return; } set\u0026lt;int\u0026gt;::iterator it; for(it = wordlens.begin(); it != wordlens.end(); it++) { int len = *it; if(start + len \u0026gt; s.length()) return; string tmp = string(s, start, len); if(dict.find(tmp) != dict.end()) { string itembp = item; if(start != 0) item += \u0026#34; \u0026#34;; item += tmp; findSen(s, start + len, dict, item); item = itembp; } } } }; ","date":"2015-05-23T03:16:58Z","permalink":"https://blog.coinidea.com/en/p/leetcode_140word-break-ii/","title":"[leetcode_140]Word Break II"},{"content":"BFS + path storage. The main effort was optimizing for time. Managed to get it down to 1500ms using map \u0026ndash; so satisfying.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 struct NodeString { vector\u0026lt;NodeString *\u0026gt; before; string now; }; class Solution { public: vector\u0026lt;vector\u0026lt;string\u0026gt;\u0026gt; result; vector\u0026lt;vector\u0026lt;string\u0026gt;\u0026gt; findLadders(string start, string end, unordered_set\u0026lt;string\u0026gt; \u0026amp;dict) { // Note: The Solution object is instantiated only once and is reused by each test case. result.clear(); if (dict.find(start) == dict.end()) { dict.insert(start); } if (dict.find(end) == dict.end()) { dict.insert(end); } map\u0026lt;string, NodeString *\u0026gt; maps; maps.clear(); maps.insert(map\u0026lt;string, NodeString *\u0026gt;::value_type(start, NULL)); vector\u0026lt;NodeString *\u0026gt; strs, strsc; strs.clear(); NodeString *nodeString = new NodeString(); nodeString-\u0026gt;before.clear(); nodeString-\u0026gt;now = start; strs.push_back(nodeString); bool isFind = false; while (true) { map\u0026lt;string, NodeString *\u0026gt; mapstmp; mapstmp.clear(); strsc.clear(); for (int i = 0; i \u0026lt; strs.size(); i++) { string item = strs[i]-\u0026gt;now; for (int j = 0; j \u0026lt; item.length(); j++) { for (char c = \u0026#39;a\u0026#39;; c \u0026lt;= \u0026#39;z\u0026#39;; c++) { string tmp = item; if (c != item[j]) { tmp[j] = c; if (dict.find(tmp) != dict.end()) { if (maps.find(tmp) == maps.end()) { NodeString *nodetmp = new NodeString(); nodetmp-\u0026gt;before.clear(); nodetmp-\u0026gt;before.push_back(strs[i]); nodetmp-\u0026gt;now = tmp; if (tmp == end) { isFind = true; vector\u0026lt;string\u0026gt; items; items.clear(); // items.push_back(end); genResult(nodetmp, items); continue; } strsc.push_back(nodetmp); maps.insert(map\u0026lt;string, NodeString *\u0026gt;::value_type(tmp, nodetmp)); mapstmp.insert(map\u0026lt;string, NodeString *\u0026gt;::value_type(tmp, nodetmp)); } else { if (tmp != start) { map\u0026lt;string, NodeString *\u0026gt;::iterator it = mapstmp.find(tmp); if (it != mapstmp.end()) it-\u0026gt;second-\u0026gt;before.push_back(strs[i]); } } } } } } } if (strsc.size() == 0 || isFind) break; strs.clear(); for (int i = 0; i \u0026lt; strsc.size(); i++) { strs.push_back(strsc[i]); } } return result; } private: void genResult(NodeString *nodeString, vector\u0026lt;string\u0026gt; \u0026amp;items) { if (nodeString-\u0026gt;before.size() == 0) { items.push_back(nodeString-\u0026gt;now); vector\u0026lt;string\u0026gt; itemsr; itemsr.clear(); vector\u0026lt;string\u0026gt;::reverse_iterator rit; for (rit = items.rbegin(); rit != items.rend(); rit++) { itemsr.push_back(*rit); } result.push_back(itemsr); items.pop_back(); } else { for (int i = 0; i \u0026lt; nodeString-\u0026gt;before.size(); i++) { items.push_back(nodeString-\u0026gt;now); genResult(nodeString-\u0026gt;before[i], items); items.pop_back(); } } } }; ","date":"2015-05-23T03:16:05Z","permalink":"https://blog.coinidea.com/en/p/leetcode_126word-ladder-ii/","title":"[leetcode_126]Word Ladder II"},{"content":"Shortest path in a graph T+T\nI only learned this from reading others\u0026rsquo; blogs. Before that, I was naively using BFS+map,\nwhich kept timing out.\nLater I also thought of finding adjacent nodes, and I was just one step away from the shortest path solution. Quite embarrassing.\nHere is the TLE code for now; I\u0026rsquo;ll revise it to use shortest path tomorrow.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Solution { public: int ladderLength(string start, string end, unordered_set\u0026lt;string\u0026gt; \u0026amp;dict) { // Note: The Solution object is instantiated only once and is reused by each test case. if(dict.find(start) == dict.end()) { dict.insert(start); } if(dict.find(end) == dict.end()) { dict.insert(end); } map\u0026lt;string,bool\u0026gt; maps; maps.clear(); maps.insert(map\u0026lt;string,bool\u0026gt;::value_type(start,true)); vector\u0026lt;string\u0026gt; strs,strsc; strs.clear(); strs.push_back(start); int count = 1; while(true) { strsc.clear(); count++; for(int i = 0;i \u0026lt; strs.size();i++) { string item = strs[i]; for(int j = 0;j \u0026lt; item.length();j++) { for(char c = \u0026#39;a\u0026#39;;c \u0026lt;= \u0026#39;z\u0026#39;;c++) { string tmp = item; if(c != item[j]) { tmp[j] = c; if(dict.find(tmp) != dict.end() \u0026amp;\u0026amp; maps.find(tmp) == maps.end()) { strsc.push_back(tmp); if(tmp == end) return count; maps.insert(map\u0026lt;string,bool\u0026gt;::value_type(tmp,true)); } } } } } if(strsc.size() == 0) break; strs.clear(); for(int i = 0;i \u0026lt; strsc.size();i++) { strs.push_back(strsc[i]); } } return 0; } }; ","date":"2015-05-23T03:15:01Z","permalink":"https://blog.coinidea.com/en/p/leetcode_127word-ladder/","title":"[leetcode_127]Word Ladder"},{"content":"Two pointers: the first pointer starts at the first character, and we enumerate the second pointer\u0026rsquo;s position from left to right. Once all target characters are covered, slide the first pointer forward to see if the condition still holds. Find the minimum window that satisfies the condition.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution { public: int letters1[256]; int letters2[256]; string minWindow(string S, string T) { for(int k = 0;k \u0026lt; 256;k++) { letters1[k] = 0; letters2[k] = 0; } for(int k = 0;k \u0026lt; T.length();k++) { letters1[T[k]]++; letters2[T[k]]++; } int min = S.length()+T.length(); int start,end; int count = T.length(); int i = 0; for(int j = 0;j \u0026lt; S.length();j++) { if(letters2[S[j]] \u0026gt; 0) { letters1[S[j]]--; if(letters1[S[j]] \u0026gt;= 0)count--; } if(count == 0) { while(true) { if(letters2[S[i]] \u0026gt; 0) { if(letters1[S[i]] \u0026lt; 0) letters1[S[i]]++; else break; } i++; } if(j - i + 1 \u0026lt; min) { min = j - i + 1; start = i; end = j; } } } if(min == S.length()+T.length())return \u0026#34;\u0026#34;; return string(S,start,end - start + 1); } }; ","date":"2015-05-23T03:14:00Z","permalink":"https://blog.coinidea.com/en/p/leetcode_76minimum-window-substring/","title":"[leetcode_76]Minimum Window Substring"},{"content":"Solved using brute force.\nUsed a map to look up whether the current fixed-length substring is one that is \u0026ldquo;needed\u0026rdquo; (i.e., needs to be found).\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 class Solution { public: bool *flag; int len; vector\u0026lt;int\u0026gt; result; vector\u0026lt;int\u0026gt; copy; int sum; vector\u0026lt;int\u0026gt; findSubstring(string S, vector\u0026lt;string\u0026gt; \u0026amp;L) { result.clear(); if(L.size() \u0026lt;= 0) return result; map\u0026lt;string,int\u0026gt; mapr; mapr.clear(); vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; rtable; rtable.clear(); len = L[0].size(); map\u0026lt;string,int\u0026gt;::iterator it; for(int i = 0; i \u0026lt; L.size(); i++) { it = mapr.find(L[i]); if(it != mapr.end()) { it-\u0026gt;second += 1; } else mapr.insert(map\u0026lt;string,bool\u0026gt;::value_type(L[i],1)); } copy.clear(); sum = 0; for(it = mapr.begin(); it != mapr.end(); it++) { copy.push_back(it-\u0026gt;second); sum += it-\u0026gt;second; } bfs(mapr, S, 0); return result; } private: void bfs(map\u0026lt;string,int\u0026gt; \u0026amp;mapr, string \u0026amp;S, int start) { if(S.length() - start \u0026lt; sum * len) return; int position; map\u0026lt;string,int\u0026gt;::iterator it; int min = S.length(); for(it = mapr.begin(); it != mapr.end(); it++) { string item = it-\u0026gt;first; if((position = S.find(item,start)) == string::npos) return; if(position \u0026lt; min) min = position; } int i = 0; int end; if(bfsStep(mapr,min,S,end)) { end = min + 1; result.push_back(min); } end = min + 1; if(end \u0026gt;= S.length()) return; return bfs(mapr, S, end); } void resetMapr(map\u0026lt;string,int\u0026gt; \u0026amp;mapr) { int i = 0; map\u0026lt;string,int\u0026gt;::iterator it; for(it = mapr.begin(); it != mapr.end(); it++) { it-\u0026gt;second = copy[i++]; } } bool bfsStep(map\u0026lt;string,int\u0026gt; \u0026amp;mapr, int pos, string \u0026amp;S, int \u0026amp;end) { int count = 0; map\u0026lt;string,int\u0026gt;::iterator it; int i; for(i = pos; i \u0026lt; S.length(); i+=len) { it = mapr.find(string(S, i, len)); if(it == mapr.end() || it-\u0026gt;second \u0026lt;= 0) { end = i+len; resetMapr(mapr); return false; } it-\u0026gt;second--; count++; if(count == sum) { resetMapr(mapr); return true; } } resetMapr(mapr); if(count == sum) return true; end = i; return false; } }; ","date":"2015-05-23T03:12:59Z","permalink":"https://blog.coinidea.com/en/p/leetcode_30substring-with-concatenation-of-all-words/","title":"[leetcode_30]Substring with Concatenation of All Words"},{"content":"A message containing letters from A-Z is being encoded to numbers using the following mapping:\n‘A’ -\u0026gt; 1\n‘B’ -\u0026gt; 2\n…\n‘Z’ -\u0026gt; 26\nGiven an encoded message containing digits, determine the total number of ways to decode it.\nFor example,\nGiven encoded message “12”, it could be decoded as “AB” (1 2) or “L” (12).\nThe number of ways decoding “12” is 2.\nInitially I used search, which timed out.\nThen I realized that if we search from the end, many redundant states can not only be stored but also avoid redundant computation.\nAlso pay attention to the case where 0 is present.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public: int counts[10000]; int numDecodings(string s) { if(s.length() \u0026lt;= 0 || (s.length() == \u0026#39;1\u0026#39; \u0026amp;\u0026amp; s[0] == \u0026#39;0\u0026#39;))return 0; if(s[s.length()-1] != \u0026#39;0\u0026#39;)counts[s.length() - 1] = 1; else counts[s.length()-1] = 0; counts[s.length()] = 1; for(int i = s.length()-2;i \u0026gt;= 0;i--) { if(s[i] == \u0026#39;0\u0026#39;) { counts[i] = 0; continue; } if(s[i] == \u0026#39;1\u0026#39; || (s[i] == \u0026#39;2\u0026#39;\u0026amp;\u0026amp;s[i+1] \u0026lt;= \u0026#39;6\u0026#39;))counts[i] = counts[i+1] + counts[i+2]; else counts[i] = counts[i+1]; } return counts[0]; } }; ","date":"2015-05-23T03:11:56Z","permalink":"https://blog.coinidea.com/en/p/leetcode_91decode-ways/","title":"[leetcode_91]Decode Ways"},{"content":"Determine the maximum number of points from a set that lie on the same line.\nSeeing the low acceptance rate made me nervous, but the other problems were getting harder and I could not solve them.\nSo I came up with an O(n^3) approach \u0026ndash; could it pass? I thought about optimizing: represent each line as:\nax + by + c = 0\nwhere a is always positive.\nThe optimization was to use a hash_map to check whether a given (a, b, c) has already been computed. It is not a great optimization.\nBut the result was surprising: without optimization it ran in 16ms, with optimization 284ms. The reason is that I used map, whose lookup is O(log n) instead of O(1).\nAnyway, it did not pass on the first try either \u0026ndash; note the edge case of duplicate points.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 class Solution { public: int maxPoints(vector\u0026lt;Point\u0026gt; \u0026amp;points) { vector\u0026lt;Point\u0026gt; pointstmp; pointstmp.clear(); int counts[1000]; for(int i = 0; i \u0026lt; points.size(); i++) { int tmp = 0; int j; for(j = 0; j \u0026lt; pointstmp.size(); j++) { if(pointstmp[j].x == points[i].x \u0026amp;\u0026amp; pointstmp[j].y == points[i].y) { break; } } if(j \u0026lt; pointstmp.size()) { counts[j]++; } else { pointstmp.push_back(points[i]); counts[pointstmp.size()-1] = 1; } } if(pointstmp.size() == 0) return 0; if(pointstmp.size() == 1) return counts[0]; if(pointstmp.size() == 2) return counts[0] + counts[1]; int ans = 2; map\u0026lt;vector\u0026lt;int\u0026gt;, bool\u0026gt; mapv; mapv.clear(); for(int i = 0; i \u0026lt; pointstmp.size()-2; i++) { for(int j = i+1; j \u0026lt; pointstmp.size()-1; j++) { int x1 = pointstmp[i].x; int y1 = pointstmp[i].y; int x2 = pointstmp[j].x; int y2 = pointstmp[j].y; if(x1 == x2 \u0026amp;\u0026amp; y1 == y2) continue; int a = y1 - y2; int b = -(x1 - x2); int c = (x1 - x2) * y1 - (y1 - y2) * x1; // if(a \u0026lt; 0) { // a = a * (-1); // b = b * (-1); // c = c * (-1); // } // vector\u0026lt;int\u0026gt; tmp; // tmp.clear(); // tmp.push_back(a); // tmp.push_back(b); // tmp.push_back(c); // if(mapv.find(tmp) != mapv.end()) continue; // mapv.insert(map\u0026lt;vector\u0026lt;int\u0026gt;, bool\u0026gt;::value_type(tmp, true)); int count = counts[i] + counts[j]; for(int k = j+1; k \u0026lt; pointstmp.size(); k++) { int x = pointstmp[k].x; int y = pointstmp[k].y; if(isInLine(a, b, c, x, y)) count += counts[k]; } if(count \u0026gt; ans) ans = count; } } return ans; } private: bool isInLine(int a, int b, int c, int x, int y) { return a * x + b * y + c == 0; } }; ","date":"2015-05-23T03:08:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode_149max-points-on-a-line/","title":"[leetcode_149]Max Points on a Line"},{"content":"Initially used search, TLE:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Solution { public: int ans; int minCut(string s) { ans = 0xffffff; if(s.length() \u0026lt;= 0)return ans; bool *flag = new bool[s.length()+1]; for(int i = 0;i \u0026lt;= s.length();i++) flag[i] = false; flag[0] = true; PartitionStep(s,1,flag); return ans; } private: void PartitionStep(string s,int step,bool *flag) { if(step == s.length()) { int i; flag[step] = true; for(i = step-1;i \u0026gt;= 0;i--) { if(flag[i] == true)break; } if(IsPalindrome(s,i,step-1)) { int count = 0; for(int i = 0;i \u0026lt;=step;i++) { if(flag[i] == true)count++; } if(count-2 \u0026lt; ans)ans = count-2; } flag[step] =false; return ; } flag[step] = true; int i; for(i = step-1;i \u0026gt;= 0;i--) { if(flag[i] == true)break; } if(IsPalindrome(s,i,step-1)) { PartitionStep(s,step+1,flag); } flag[step] = false; PartitionStep(s,step+1,flag); } bool IsPalindrome(string s,int i,int j) { while(i \u0026lt; j) { if(s[i] != s[j])return false; i++; j--; } return true; } }; Later I used DP. I must admit I studied someone else\u0026rsquo;s approach:\nhttp://blog.csdn.net/doc_sgl/article/details/13418125\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public: int minCut(string s) { int lens = s.length(); bool **isP; isP = new bool *[lens]; for(int i = 0;i \u0026lt; lens;i++) { isP[i] = new bool [lens]; for(int j = 0;j \u0026lt; lens;j++) { isP[i][j] = false; } } for(int i = 0;i \u0026lt; lens;i++) isP[i][i] = true; int * dp = new int[lens+1]; for(int i = lens;i \u0026gt;= 0;i--) dp[i] = lens - 1 - i; for(int i = lens-1;i \u0026gt;= 0;i--) { for(int j = i;j \u0026lt; lens;j++) { if(((j - i) \u0026lt;= 2 || isP[i+1][j-1]) \u0026amp;\u0026amp; s[i] == s[j]) { isP[i][j] = true; dp[i] = dp[i] \u0026gt; dp[j+1]+1?dp[j+1]+1:dp[i]; } } } return dp[0]; } }; ","date":"2015-05-23T03:07:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode_132palindrome-partitioning-ii/","title":"[leetcode_132]Palindrome Partitioning II"},{"content":"Find the maximum path sum in a binary tree.\nGiven a binary tree, find the maximum path sum.\nThe path may start and end at any node in the tree.\nFor example:\nGiven the below binary tree,\n1 2 3 1 / \\ 2 3 Return 6.\nRecursively explore all cases. For each node, the answer is: max(node value alone, left subtree max contribution + node value, left subtree max contribution + node value + right subtree max contribution, node value + right subtree max contribution).\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Solution { public: int result; int maxPathSum(TreeNode *root) { result = 0x80000001; if(root != NULL) { queryNodes(root); } return result; } private: void queryNodes(TreeNode *node) { if(node-\u0026gt;left == NULL \u0026amp;\u0026amp; node-\u0026gt;right == NULL) { if(node-\u0026gt;val \u0026gt; result) result = node-\u0026gt;val; return; } if(node-\u0026gt;left == NULL) { queryNodes(node-\u0026gt;right); node-\u0026gt;val = node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val \u0026gt;= node-\u0026gt;val ? node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val : node-\u0026gt;val; if(node-\u0026gt;val \u0026gt; result) result = node-\u0026gt;val; return; } if(node-\u0026gt;right == NULL) { queryNodes(node-\u0026gt;left); node-\u0026gt;val = node-\u0026gt;val + node-\u0026gt;left-\u0026gt;val \u0026gt;= node-\u0026gt;val ? node-\u0026gt;val + node-\u0026gt;left-\u0026gt;val : node-\u0026gt;val; if(node-\u0026gt;val \u0026gt; result) result = node-\u0026gt;val; return; } queryNodes(node-\u0026gt;right); queryNodes(node-\u0026gt;left); if(node-\u0026gt;val \u0026gt; result) result = node-\u0026gt;val; if(node-\u0026gt;val + node-\u0026gt;left-\u0026gt;val \u0026gt; result) result = node-\u0026gt;val + node-\u0026gt;left-\u0026gt;val; if(node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val \u0026gt; result) result = node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val; if(node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val + node-\u0026gt;left-\u0026gt;val \u0026gt; result) result = node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val + node-\u0026gt;left-\u0026gt;val; int max = node-\u0026gt;val + node-\u0026gt;left-\u0026gt;val \u0026gt;= node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val ? node-\u0026gt;val + node-\u0026gt;left-\u0026gt;val : node-\u0026gt;val + node-\u0026gt;right-\u0026gt;val; node-\u0026gt;val = max \u0026gt;= node-\u0026gt;val ? max : node-\u0026gt;val; } }; ","date":"2015-05-23T03:06:12Z","permalink":"https://blog.coinidea.com/en/p/leetcode_124binary-tree-maximum-path-sum/","title":"[leetcode_124]Binary Tree Maximum Path Sum"},{"content":"Basic singly linked list operations including reversing and calculating length.\nThe problem requires:\n1-\u0026gt;2-\u0026gt;3-\u0026gt;4 =\u0026gt; 1-\u0026gt;4-\u0026gt;2-\u0026gt;3, an interleaving operation.\nGiven a singly linked list L: L0-\u0026gt;L1-\u0026gt;\u0026hellip;-\u0026gt;Ln-1-\u0026gt;Ln,\nreorder it to: L0-\u0026gt;Ln-\u0026gt;L1-\u0026gt;Ln-1-\u0026gt;L2-\u0026gt;Ln-2-\u0026gt;\u0026hellip;\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Solution { public: void reorderList(ListNode *head) { int len = getLength(head); if(len \u0026lt;= 2)return ; int pos = len%2==0?len/2:len/2+1; ListNode * headend = getListNode(head,pos-1); ListNode * head2 = getListNode(head,pos); headend -\u0026gt; next = NULL; head2 = reverseListNode(head2); ListNode * headc = head; while(head2 != NULL) { ListNode * headnext = head-\u0026gt;next; ListNode * head2next = head2-\u0026gt;next; head-\u0026gt;next = head2; head2-\u0026gt;next = headnext; head = headnext; head2 = head2next; } head = headc; } private: ListNode * reverseListNode(ListNode * head) { ListNode * before = head; ListNode * now = head-\u0026gt;next; while(now != NULL) { ListNode * next = now-\u0026gt;next; now-\u0026gt;next = before; before = now; now = next; } head-\u0026gt;next = NULL; return before; } int getLength(ListNode *head) { int len = 0; while(head != NULL) { len++; head = head-\u0026gt;next; } return len; } ListNode *getListNode(ListNode *head,int pos) { int i = 0; while(i \u0026lt; pos) { head = head-\u0026gt;next; i++; } return head; } }; ","date":"2015-05-23T03:05:13Z","permalink":"https://blog.coinidea.com/en/p/leetcode_143reorder-list/","title":"[leetcode_143]Reorder List"},{"content":"Search with pruning. However, there was a strange issue where one test case would not pass. I had to add a pruning condition specifically for that test case to get AC. So I should really look into the DP approach. At the time I kept trying to use a greedy method, but clearly there are many places requiring backtracking, so the greedy approach does not work well. Also note that a* should be treated as a unit \u0026ndash; it represents the empty string or a string of multiple as.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Solution { public: bool result; bool isMatch(const char *s, const char *p) { // Note: The Solution object is instantiated only once and is reused by each test case. result = false; int lens = strlen(s); int lenp = strlen(p); if(p[lenp-1] != \u0026#39;*\u0026#39; \u0026amp;\u0026amp; s[lens-1] != p[lenp-1] \u0026amp;\u0026amp; p[lenp-1]!=\u0026#39;.\u0026#39;)return result; matchStep(s,p); return result; } private: void matchStep(const char * s,const char * p) { if(result)return; if(*s == \u0026#39;\\0\u0026#39; \u0026amp;\u0026amp; *p == \u0026#39;\\0\u0026#39;) { result = true; return; } if(*s == \u0026#39;\\0\u0026#39;) { if(*(p+1) == \u0026#39;*\u0026#39;) { matchStep(s,p+2); return ; } } if(*s == \u0026#39;\\0\u0026#39; || *p == \u0026#39;\\0\u0026#39;)return; if(*(p+1) != \u0026#39;\\0\u0026#39;) { if(*(p+1) != \u0026#39;*\u0026#39;) { if(*s == *p || *p == \u0026#39;.\u0026#39;) { matchStep(s+1,p+1); } else return; } else { if(*s != *p \u0026amp;\u0026amp; *p != \u0026#39;.\u0026#39;) { matchStep(s,p+2); } else { matchStep(s,p+2); matchStep(s+1,p); matchStep(s+1,p+2); } } } else { if(*s == *p || *p == \u0026#39;.\u0026#39;) { matchStep(s+1,p+1); } else return; } } }; ","date":"2015-05-23T03:04:11Z","permalink":"https://blog.coinidea.com/en/p/leetcode_10regular-expression-matching/","title":"[leetcode_10]Regular Expression Matching"},{"content":"I originally wanted to use KMP, but my getNext implementation was terrible and timed out.\nI have been really exhausted lately. I will take a break for a while. I passed using naive pattern matching instead.\nAfter some time I will practice again. For now I will read Kernighan and Ritchie\u0026rsquo;s \u0026ldquo;The C Programming Language\u0026rdquo; and \u0026ldquo;Computer Systems: A Programmer\u0026rsquo;s Perspective.\u0026rdquo; I am truly tired and under a lot of pressure.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public: char *strStr(char *haystack, char *needle) { int lenh = strlen(haystack); int lenn = strlen(needle); if(lenh == 0 \u0026amp;\u0026amp; lenn == 0)return haystack; for(int i = 0;i \u0026lt; lenh;i++) { if(strlen(haystack + i) \u0026gt;= lenn\u0026amp;\u0026amp;isEqual(haystack,i,needle))return haystack + i; } return NULL; } private: bool isEqual(char *haystack,int i,char * needle) { int j; for(j = 0;j \u0026lt; strlen(needle);j++) { if(needle[j] != haystack[i+j])break; } if(j == strlen(needle))return true; else return false; } }; KMP:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public: int lenh; int lenn; int *next; char *strStr(char *haystack, char *needle) { lenh = strlen(haystack); lenn = strlen(needle); if(lenn == 0)return haystack; if(lenh \u0026lt; lenn)return NULL; next = new int[lenn]; getNext(needle); int k = 0; int j = 0; while(j \u0026lt; lenh) { if(k == -1 || needle[k] == haystack[j]) { k++; j++; if(k == lenn)return haystack + j - lenn; } else k = next[k]; } return NULL; } private: void getNext(char *needle) { int k = -1; int j = 0; next[j] = k; while(j \u0026lt; lenn-1) { if(k == -1 || needle[k] == needle[j]) { k++; j++; next[j] = k; } else k = next[k]; } } }; ","date":"2015-05-23T03:02:31Z","permalink":"https://blog.coinidea.com/en/p/leetcode_28implement-strstr/","title":"[leetcode_28]Implement strStr()"},{"content":"This problem asks you to determine whether a string is a valid number. However, the test cases are quite tricky\u0026hellip; Perhaps I am just not skilled enough \u0026ndash; my definition didn\u0026rsquo;t match the expected output, and I had to fix it many times. No wonder the acceptance rate for this problem is so low.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 class Solution { public: bool isNumber(const char *s) { string str = \u0026#34;\u0026#34;; int len = strlen(s); int i = 0; for(;i \u0026lt; len;i++) { if(s[i] == \u0026#39; \u0026#39;)continue; else break; } for(;i \u0026lt; len;i++) { str.push_back(s[i]); } for(int i = str.length()-1;i \u0026gt;= 0;i--) { if(str[i] == \u0026#39; \u0026#39;) { str.erase(i); } else break; } return isNumberString(str); } private: bool isNumberString(string s) { // Does it have a sign? // Does it have a decimal point? // Does it contain \u0026#39;e\u0026#39;? // Does it have leading zeros? int len = s.length(); if(len \u0026lt;= 0)return false; if(len == 1) { if(s[0] \u0026lt; \u0026#39;0\u0026#39; || s[0] \u0026gt; \u0026#39;9\u0026#39;)return false; else return true; } int start = 0; if(s[0] == \u0026#39;+\u0026#39; || s[0] == \u0026#39;-\u0026#39;) { start = 1; } bool isZeroAllowed = true; bool isPotAllowed = false; bool isEallowed = false; bool once = true; if(s[start] == \u0026#39;.\u0026#39;) { if(len \u0026gt;= start + 2) { if(s[start + 1] \u0026gt;= \u0026#39;0\u0026#39; \u0026amp;\u0026amp; s[start + 1] \u0026lt;= \u0026#39;9\u0026#39;) { isZeroAllowed = true; isPotAllowed = false; isEallowed = true; once = false; start = start + 2; } else return false; } else return false; } for(int i = start;i \u0026lt; len;i++) { if(s[i] == \u0026#39;.\u0026#39; \u0026amp;\u0026amp; isPotAllowed == false) { return false; } if(s[i] == \u0026#39;.\u0026#39; \u0026amp;\u0026amp; isPotAllowed == true) { isPotAllowed = false; continue; } if(s[i] == \u0026#39;e\u0026#39; \u0026amp;\u0026amp; isEallowed == false) { return false; } if(s[i] == \u0026#39;e\u0026#39; \u0026amp;\u0026amp; isEallowed == true) { isEallowed = false; isPotAllowed = false; once = false; if(i + 1 \u0026gt;= len)return false; if(s[i+1] == \u0026#39;-\u0026#39; || s[i+1] == \u0026#39;+\u0026#39;) { if(i+2 \u0026gt;= len)return false; if(s[i+2] \u0026lt; \u0026#39;0\u0026#39; || s[i+2] \u0026gt; \u0026#39;9\u0026#39;)return false; i+=2; continue; } if(s[i+1] \u0026lt; \u0026#39;0\u0026#39; || s[i+1] \u0026gt; \u0026#39;9\u0026#39;)return false; continue; } if(s[i] \u0026gt;= \u0026#39;0\u0026#39; \u0026amp;\u0026amp; s[i] \u0026lt;= \u0026#39;9\u0026#39;) { if(once == true) { isZeroAllowed = true; isPotAllowed = true; isEallowed = true; once = false; } continue; } return false; } return true; } }; ","date":"2015-05-23T03:00:04Z","permalink":"https://blog.coinidea.com/en/p/leetcode_65valid-number/","title":"[leetcode_65]Valid Number"},{"content":"Simulate integer division without using multiplication, modulo, or division operators.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public: double exp[100]; int divide(int dividend, int divisor) { return divided(dividend, divisor); } private: int divided(double dividend, double divisor) { int flag = 1; if((dividend \u0026gt; 0 \u0026amp;\u0026amp; divisor \u0026lt; 0) || (dividend \u0026lt; 0 \u0026amp;\u0026amp; divisor \u0026gt; 0)) flag = -1; if(dividend \u0026lt; 0) { dividend = abs(dividend); } if(divisor \u0026lt; 0) { divisor = abs(divisor); } int i = 0; exp[i++] = divisor; while(exp[i-1] \u0026lt; dividend) { exp[i++] = exp[i-1] + exp[i-1]; } int ans = 0; i--; while(i \u0026gt;= 0) { if(dividend \u0026gt;= exp[i]) { ans += (int)pow(2.0, i); dividend -= exp[i]; } else { i--; } } if(flag == -1) return ~ans + 1; else return ans; } }; ","date":"2015-05-23T02:58:15Z","permalink":"https://blog.coinidea.com/en/p/leetcode_29divide-two-integers/","title":"[leetcode_29]Divide Two Integers"},{"content":"Reverse Polish Notation \u0026ndash; can be solved using a stack.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution { public: int evalRPN(vector\u0026lt;string\u0026gt; \u0026amp;tokens) { stack\u0026lt;int\u0026gt; st; for(int i = 0; i \u0026lt; tokens.size(); i++) { if(tokens[i] == \u0026#34;+\u0026#34; || tokens[i] == \u0026#34;-\u0026#34; || tokens[i] == \u0026#34;*\u0026#34; || tokens[i] == \u0026#34;/\u0026#34;) { int num1 = st.top(); st.pop(); int num2 = st.top(); st.pop(); if(tokens[i] == \u0026#34;+\u0026#34;) { st.push(num1 + num2); } else if(tokens[i] == \u0026#34;-\u0026#34;) { st.push(num2 - num1); } else if(tokens[i] == \u0026#34;*\u0026#34;) { st.push(num1 * num2); } else if(tokens[i] == \u0026#34;/\u0026#34;) { st.push(num2 / num1); } } else { st.push(genNum(tokens[i])); } } return st.top(); } private: int genNum(string s) { int flag = 1; if(s[0] == \u0026#39;-\u0026#39;) { flag = -1; s = string(s, 1); } int num = 0; for(int i = s.length() - 1; i \u0026gt;= 0; i--) { num += (s[i] - \u0026#39;0\u0026#39;) * (int)pow(10.0, (int)s.length() - 1 - i); } return num * flag; } }; ","date":"2015-05-23T02:57:15Z","permalink":"https://blog.coinidea.com/en/p/leetcode_150-evaluate-reverse-polish-notation/","title":"[leetcode_150] Evaluate Reverse Polish Notation"},{"content":"Children are standing in a line to receive candy. Each child must receive at least one candy, and each child has a rating. Children with higher ratings must have more candy than their neighbors.\nWhat is the minimum number of candies needed?\nSimulate in order: assume the first child gets one candy. If the next child has a lower rating, the next child gets one fewer, and the previous child\u0026rsquo;s count increases by one. We need to track how many children before each child have consecutively higher ratings.\nIf the next child has a higher rating, they get one more candy than the previous child. Simulate accordingly. However, I got Wrong Answer many times T_T.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Solution { public: int candy(vector\u0026lt;int\u0026gt; \u0026amp;ratings) { int len = ratings.size(); if(len == 0 || len == 1)return len; vector\u0026lt;int\u0026gt;bigger(ratings.size(),0); int count = 1; int now = 1; int max = 0; int i; for(i = 1;i \u0026lt; ratings.size();i++) { if(ratings[i] \u0026gt; ratings[i-1]) { if(max != 0) { if(bigger[i-1] \u0026lt; max-1) { count += max-1 - bigger[i-1]; } } max = 0; bigger[i] = 0; now += 1; count += now; } else if(ratings[i] \u0026lt; ratings[i-1]) { bigger[i] = bigger[i-1] + 1; if(now == 1) { count += bigger[i] + now; } else { max = now; now = 1; count += bigger[i] + now - (max-1); } } else { if(max != 0) { if(bigger[i-1] \u0026lt; max-1) { count += max-1 - bigger[i-1]; } } max = 0; bigger[i] = 0; now = 1; count += 1; } } if(max != 0) { if(bigger[i-1] \u0026lt; max-1) { count += max-1 - bigger[i-1]; } } return count; } }; ","date":"2015-05-23T02:56:07Z","permalink":"https://blog.coinidea.com/en/p/leetcode_135candy/","title":"[leetcode_135]Candy"},{"content":"Simplify the input path to a Unix-style path. This can be solved using a stack.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public: string simplifyPath(string path) { vector\u0026lt;string\u0026gt; paths; paths.clear(); char * split = strtok(const_cast\u0026lt;char*\u0026gt;(path.c_str()), \u0026#34;/\u0026#34;); while(split != NULL) { paths.push_back(split); split = strtok(NULL, \u0026#34;/\u0026#34;); } stack\u0026lt;char*\u0026gt; st; for(int i = 0; i \u0026lt; paths.size(); i++) { if(strcmp(paths[i], \u0026#34;.\u0026#34;) == 0) continue; if(strcmp(paths[i], \u0026#34;..\u0026#34;) == 0) { if(!st.empty()) st.pop(); } else { st.push(paths[i]); } } paths.clear(); while(!st.empty()) { paths.push_back(st.top()); st.pop(); } string spath = \u0026#34;\u0026#34;; for(int i = paths.size() - 1; i \u0026gt;= 0; i--) { spath = spath + string(\u0026#34;/\u0026#34;); spath = spath + string(paths[i]); } if(spath == \u0026#34;\u0026#34;) spath = spath + string(\u0026#34;/\u0026#34;); return spath; } }; ","date":"2015-05-23T02:55:03Z","permalink":"https://blog.coinidea.com/en/p/leetcode_71simplify-path/","title":"[leetcode_71]Simplify Path"},{"content":"Given a dictionary, determine whether the input word can be segmented into words found in the dictionary.\nBrute force with pruning.\nInitially it timed out. I added an extra check to verify whether all characters in the current substring exist in the dictionary. But I feel like I may have exploited a weakness in the test data.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution { public: bool result; bool letters[26]; bool wordBreak(string s, unordered_set\u0026lt;string\u0026gt; \u0026amp;dict) { result = false; for(int i = 0;i \u0026lt; 26;i++) letters[i] = false; for(string it:dict) { for(int i = 0;i \u0026lt; it.length();i++) { letters[it[i] - \u0026#39;a\u0026#39;] = true; } } for(int i = s.length();i \u0026gt; 0;i--) { if(existLetters(string(s,0,i)) == false)return false; if(dict.find(string(s,0,i)) != dict.end()) { if(i == s.length())return true; else { wordBreakStep(s,i,dict); } } } return result; } private: bool existLetters(string s) { for(int i = 0;i \u0026lt; s.length();i++) { if(letters[s[i] - \u0026#39;a\u0026#39;] == false)return false; } return true; } void wordBreakStep(string s,int start,unordered_set\u0026lt;string\u0026gt; \u0026amp;dict) { if(result == true)return; for(int i = s.length() - start;i \u0026gt; 0;i--) { if(existLetters(string(s,start,i)) == false)return; if(dict.find(string(s,start,i)) != dict.end()) { if(i == s.length()-start) { result = true; return; } else { wordBreakStep(s,start + i,dict); } } } } }; ","date":"2015-05-23T02:53:55Z","permalink":"https://blog.coinidea.com/en/p/leetcode_139word-break/","title":"[leetcode_139]Word Break"},{"content":"Given strings s1 and s2, determine whether s3 is formed by interleaving s1 and s2 while preserving their original order.\nInitially I tried simulation, but there is a problem: what if s1[p1] and s2[p2] are both equal to s3[p3]? In that case, we would need to save state and perform a search.\nAs expected, it timed out.\nI found online that DP can be used:\nf[i][j] = f[i-1][j] + s1[i] \u0026amp;\u0026amp; s1[i] == s3[k]\nf[i][j] = f[i][j-1](i+j = k) \u0026amp;\u0026amp; s2[j] == s3[j]\nThe k-th character in s3 is fully matched only when it equals either the i-th character of s1 or the j-th character of s2.\nEnumerate all cases, at most n^2.\nOutput f[i][j] where i = s1.length(), j = s2.length(), and i+j = s3.length().\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public: bool ***f; bool isInterleave(string s1, string s2, string s3) { if(s1.length() + s2.length() != s3.length())return false; bool f[500][500]; for(int i = 0;i \u0026lt; 500;i++) { for(int j = 0;j \u0026lt; 500;j++) { f[i][j] = false; } } f[0][0] = true; for(int i = 1;i \u0026lt;= s3.length();i++) { for(int j = 0;j \u0026lt; i;j++) { if(f[j][i-1-j] \u0026amp;\u0026amp; i-1-j\u0026lt;=s2.length() \u0026amp;\u0026amp; j+1 \u0026lt;= s1.length() \u0026amp;\u0026amp; s1[j] == s3[i-1]) { f[j+1][i-1-j] = true; } if(f[j][i-1-j] \u0026amp;\u0026amp; j \u0026lt;= s1.length() \u0026amp;\u0026amp; i-1-j+1 \u0026lt;= s2.length() \u0026amp;\u0026amp; s2[i-1-j] == s3[i-1]) { f[j][i-1-j+1] = true; } } } return f[s1.length()][s2.length()]; } }; ","date":"2015-05-23T02:52:47Z","permalink":"https://blog.coinidea.com/en/p/leetcode_97interleaving-string/","title":"[leetcode_97]Interleaving String"},{"content":"Find the longest substring that forms a valid parentheses sequence. This can be solved using a stack.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public: int longestValidParentheses(string s) { stack\u0026lt;int\u0026gt; st; st.push(-1); int max = 0; int i = 0; while(i \u0026lt; s.length()) { int top = st.top(); if(top == -1) { st.push(i); } else { if(s[top] == \u0026#39;(\u0026#39; \u0026amp;\u0026amp; s[i] == \u0026#39;)\u0026#39;) { st.pop(); } else { st.push(i); } } i++; } int now = s.length(); while(!st.empty()) { int before = st.top(); st.pop(); if((now - 1 - before) % 2 == 0 \u0026amp;\u0026amp; now - 1 - before \u0026gt; max) max = now - 1 - before; now = before; } return max; } }; ","date":"2015-05-23T02:51:31Z","permalink":"https://blog.coinidea.com/en/p/leetcode_32longest-valid-parentheses/","title":"[leetcode_32]Longest Valid Parentheses"},{"content":"A simple search problem.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Solution { public: bool result; bool exist(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board, string word) { vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; flag; flag.clear(); for(int i = 0; i \u0026lt; board.size(); i++) { vector\u0026lt;int\u0026gt; item(board[i].size(), 0); flag.push_back(item); } result = false; int pos = 0; for(int i = 0; i \u0026lt; board.size(); i++) { for(int j = 0; j \u0026lt; board[i].size(); j++) { if(flag[i][j] == 0 \u0026amp;\u0026amp; board[i][j] == word[pos]) { flag[i][j] = 1; pos++; existStep(board, flag, word, i, j, pos); pos--; flag[i][j] = 0; } } } return result; } private: void existStep(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board, vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;flag, string word, int x, int y, int pos) { if(result) return; if(pos \u0026gt;= word.length()) { result = true; return; } int walk[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; for(int i = 0; i \u0026lt; 4; i++) { int xn = x + walk[i][0]; int yn = y + walk[i][1]; if(xn \u0026lt; 0 || xn \u0026gt;= board.size() || yn \u0026lt; 0 || yn \u0026gt;= board[0].size()) continue; if(flag[xn][yn] == 1 || board[xn][yn] != word[pos]) continue; flag[xn][yn] = 1; pos++; existStep(board, flag, word, xn, yn, pos); pos--; flag[xn][yn] = 0; } } }; ","date":"2015-05-23T02:44:16Z","permalink":"https://blog.coinidea.com/en/p/leetcode_79word-search/","title":"[leetcode_79]Word Search"},{"content":"I solved this problem using brute force. The stack-based algorithm for finding the largest rectangle in a histogram seemed to have a high worst-case complexity.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public: int maximalRectangle(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;matrix) { int max = 0; int **map = new int*[matrix.size()]; for(int i = 0; i \u0026lt; matrix.size(); i++) { map[i] = new int[matrix[0].size()]; } for(int i = 0; i \u0026lt; matrix.size(); i++) { int height = 0; for(int j = matrix[0].size() - 1; j \u0026gt;= 0; j--) { if(matrix[i][j] == \u0026#39;1\u0026#39;) map[i][j] = ++height; else { height = 0; map[i][j] = height; } } } for(int i = 0; i \u0026lt; matrix.size(); i++) { for(int j = 0; j \u0026lt; matrix[0].size(); j++) { int width = map[i][j]; max = Max(max, width); for(int k = i + 1; k \u0026lt; matrix.size(); k++) { if(map[k][j] == 0) break; else { width = Min(width, map[k][j]); max = Max(max, width * (k - i + 1)); } } } } return max; } private: int Max(int a, int b) { return a \u0026gt; b ? a : b; } int Min(int a, int b) { return a \u0026lt; b ? a : b; } }; ","date":"2015-05-23T02:43:10Z","permalink":"https://blog.coinidea.com/en/p/leetcode_85-maximal-rectangle/","title":"[leetcode_85] Maximal Rectangle"},{"content":"Big integer multiplication.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class Solution { public: string multiply(string num1, string num2) { string ans = \u0026#34;\u0026#34;; int inbit; // gen table vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; table; table.clear(); for(int i = num1.length()-1; i \u0026gt;= 0; i--) { vector\u0026lt;int\u0026gt; item; item.clear(); inbit = 0; for(int k = 0; k \u0026lt; num1.length()-1-i; k++) item.push_back(0); for(int j = num2.length()-1; j \u0026gt;= 0; j--) { int tmp = (num1[i] - \u0026#39;0\u0026#39;) * (num2[j] - \u0026#39;0\u0026#39;) + inbit; inbit = tmp / 10; item.push_back(tmp % 10); } if(inbit != 0) item.push_back(inbit); table.push_back(item); } // calc ansint vector\u0026lt;int\u0026gt; ansint; ansint.clear(); int len = table[table.size()-1].size(); inbit = 0; for(int i = 0; i \u0026lt; len; i++) { int tmp = inbit; for(int j = 0; j \u0026lt; table.size(); j++) { if(table[j].size() \u0026gt; i) { tmp += table[j][i]; } } inbit = tmp / 10; ansint.push_back(tmp % 10); } if(inbit != 0) ansint.push_back(inbit); bool flag = false; for(int i = ansint.size()-1; i \u0026gt;= 0; i--) { if(ansint[i] == 0 \u0026amp;\u0026amp; i != 0 \u0026amp;\u0026amp; flag == false) continue; ans.push_back(ansint[i] + \u0026#39;0\u0026#39;); flag = true; } return ans; } }; ","date":"2015-05-23T02:42:03Z","permalink":"https://blog.coinidea.com/en/p/leetcode_43-multiply-strings/","title":"[leetcode_43] Multiply Strings"},{"content":"Output all possible IP addresses that can be formed from a digit string. Watch out for the case with leading zeros.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 class Solution { public: vector\u0026lt;string\u0026gt; restoreIpAddresses(string s) { vector\u0026lt;string\u0026gt; ans; ans.clear(); if(s.length() \u0026gt; 12)return ans; vector\u0026lt;int\u0026gt; split; split.clear(); split.push_back(0); for(int i = 0;i \u0026lt; s.length();i++) { int num = genInt(split[split.size()-1],i,s); if(num \u0026gt;= 0\u0026amp;\u0026amp;num \u0026lt;= 255) { split.push_back(i); searchS(s,split,ans); split.pop_back(); } } return ans; } private: int genInt(int start,int end,string s) { string numstr(s,start,end-start+1); if(numstr.length() \u0026gt;= 4)return -1; if(end \u0026gt; start \u0026amp;\u0026amp; s[start] == \u0026#39;0\u0026#39;)return -1; int num = 0; bool flag = false; for(int i = numstr.length()-1;i \u0026gt;= 0;i--) { flag = true; num += (numstr[i] - \u0026#39;0\u0026#39;)*(int)pow(10.0,(int)numstr.length() - 1 - i); } if(!flag)return -1; return num; } void searchS(string s,vector\u0026lt;int\u0026gt;\u0026amp; split,vector\u0026lt;string\u0026gt;\u0026amp; ans) { if(split.size() == 5) { string tmp = s; for(int i = 1;i \u0026lt; split.size()-1;i++) { tmp.insert(tmp.begin()+split[i]+i,\u0026#39;.\u0026#39;); } ans.push_back(tmp); return; } if(split.size() == 4) { int numlast = genInt(split[split.size()-1]+1,s.length()-1,s); if(numlast \u0026gt;= 0\u0026amp;\u0026amp;numlast \u0026lt;= 255) { split.push_back(s.length()-1); searchS(s,split,ans); split.pop_back(); } return; } for(int i = split[split.size()-1]+1;i \u0026lt; s.length();i++) { int num = genInt(split[split.size()-1]+1,i,s); if(num \u0026gt;= 0\u0026amp;\u0026amp;num \u0026lt;= 255) { split.push_back(i); searchS(s,split,ans); split.pop_back(); } } } }; ","date":"2015-05-23T02:40:56Z","permalink":"https://blog.coinidea.com/en/p/leetcode_93restore-ip-addresses/","title":"[leetcode_93]Restore IP Addresses"},{"content":"Output a matrix in spiral order. Watch out for edge cases with single rows and single columns.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 class Solution { public: vector\u0026lt;int\u0026gt; spiralOrder(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;matrix) { vector\u0026lt;int\u0026gt; ans; ans.clear(); if(matrix.size() \u0026lt;= 0) return ans; int count = 0; int sum = matrix.size() * matrix[0].size(); int px = 0; int py = 0; int xa = 0; int xb = matrix.size() - 1; int ya = 0; int yb = matrix[0].size() - 1; int dir = 0; while(count \u0026lt; sum) { ans.push_back(matrix[px][py]); switch(dir) { case 0: if(py == yb) { dir++; dir %= 4; xa++; px++; break; } py++; if(py == yb) { dir++; dir %= 4; xa++; } break; case 1: if(px == xb) { dir++; dir %= 4; yb--; py--; break; } px++; if(px == xb) { dir++; dir %= 4; yb--; } break; case 2: if(py == ya) { dir++; dir %= 4; xb--; px--; break; } py--; if(py == ya) { dir++; dir %= 4; xb--; } break; case 3: if(px == xa) { dir++; dir %= 4; ya++; py++; break; } px--; if(px == xa) { dir++; dir %= 4; ya++; } break; } count++; } return ans; } }; ","date":"2015-05-23T02:39:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode_54spiral-matrix/","title":"[leetcode_54]Spiral Matrix"},{"content":"Insert an interval, then output the merged result.\nI took a shortcut here by directly reusing the merge function from the previous problem.\nHowever, the problem states the intervals are already sorted, so the time complexity could be reduced to O(n).\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 int cmp(Interval a, Interval b) { if (a.start == b.start) return a.end \u0026lt; b.end; return a.start \u0026lt; b.start; } class Solution { public: vector\u0026lt;Interval\u0026gt; insert(vector\u0026lt;Interval\u0026gt; \u0026amp;intervals, Interval newInterval) { intervals.push_back(newInterval); return merge(intervals); } private: vector\u0026lt;Interval\u0026gt; merge(vector\u0026lt;Interval\u0026gt; \u0026amp;intervals) { sort(intervals.begin(), intervals.end(), cmp); vector\u0026lt;Interval\u0026gt; ans; ans.clear(); if (intervals.size() \u0026lt;= 0) return ans; Interval item = intervals[0]; for (int i = 1; i \u0026lt; intervals.size(); i++) { if (item.end \u0026lt; intervals[i].start) { ans.push_back(item); item = intervals[i]; } else { if (item.end \u0026lt; intervals[i].end) item.end = intervals[i].end; } } ans.push_back(item); return ans; } }; ","date":"2015-05-23T02:38:39Z","permalink":"https://blog.coinidea.com/en/p/leetcode_57insert-interval/","title":"[leetcode_57]Insert Interval"},{"content":"Merge intervals. First, sort as a preprocessing step.\nThen iterate through each interval and check if it can be merged with the following ones.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 int cmp(Interval a, Interval b) { if(a.start == b.start) return a.end \u0026lt; b.end; return a.start \u0026lt; b.start; } class Solution { public: vector\u0026lt;Interval\u0026gt; merge(vector\u0026lt;Interval\u0026gt; \u0026amp;intervals) { sort(intervals.begin(), intervals.end(), cmp); vector\u0026lt;Interval\u0026gt; ans; ans.clear(); if(intervals.size() \u0026lt;= 0) return ans; Interval item = intervals[0]; for(int i = 1; i \u0026lt; intervals.size(); i++) { if(item.end \u0026lt; intervals[i].start) { ans.push_back(item); item = intervals[i]; } else { if(item.end \u0026lt; intervals[i].end) item.end = intervals[i].end; } } ans.push_back(item); return ans; } }; ","date":"2015-05-23T02:37:38Z","permalink":"https://blog.coinidea.com/en/p/leetcode_56merge-intervals/","title":"[leetcode_56]Merge Intervals"},{"content":"Sudoku solver \u0026ndash; haha, I had a problem that tormented me for a long time before, and I had written this solver, so I just adapted it.\nFirst, there are published papers showing that puzzles with fewer than 17 given cells have no unique solution.\nThen, just use brute force. The trick is: start searching from the cells with the fewest possibilities.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 struct Pointxy { int x; int y; int val; }; int cmp(Pointxy a, Pointxy b) { return a.val \u0026lt; b.val; } class Solution { public: int bitarray[9]; int map[9][9]; bool result; int CountOnes(int v) { int number = 0; while(v) { v \u0026amp;= (v-1); number++; } return number; } int GetRegionOfBoard(int x, int y) { if(x \u0026gt;= 0 \u0026amp;\u0026amp; x \u0026lt; 3) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 0; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 1; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 2; } if(x \u0026gt;= 3 \u0026amp;\u0026amp; x \u0026lt; 6) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 3; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 4; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 5; } if(x \u0026gt;= 6 \u0026amp;\u0026amp; x \u0026lt; 9) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 6; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 7; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 8; } } bool RefeshMap(int x, int y){ int set_tmp = 0; for(int i = 0; i \u0026lt; 9; i++) { if(CountOnes(map[x][i]) == 1) { set_tmp = set_tmp | map[x][i]; } if(CountOnes(map[i][y]) == 1) { set_tmp = set_tmp | map[i][y]; } } int region = GetRegionOfBoard(x, y); int x_r = (region / 3 + 1) * 3; int y_r = (region % 3 + 1) * 3; for(int i = x_r-3; i \u0026lt; x_r; i++) { for(int j = y_r-3; j \u0026lt; y_r; j++) { if(CountOnes(map[i][j]) == 1) { set_tmp = set_tmp | map[i][j]; } } } if(set_tmp == 511)return false; map[x][y] = 511 - set_tmp; return true; } void Move(Pointxy pxy[81], int index, vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board) { if(result == true)return; if(index \u0026lt;= 0) { result = true; return; } else { sort(pxy, pxy+index, cmp); int pi = pxy[0].x; int pj = pxy[0].y; for(int ibit = 0; ibit \u0026lt; 9; ibit++) { if(result == true)return; if(map[pi][pj] \u0026amp; bitarray[ibit]) { if(pi == 0 \u0026amp;\u0026amp; pj == 6) { int hujiulin = 1; } board[pi][pj] = ibit+1+\u0026#39;0\u0026#39;; map[pi][pj] -= bitarray[ibit]; int xtmp[81]; int ytmp[81]; int indextmp = 0; for(int i = 1; i \u0026lt; index; i++) { int xi = pxy[i].x; int yi = pxy[i].y; if(xi == pi || yi == pj || GetRegionOfBoard(xi, yi) == GetRegionOfBoard(pi, pj)) { if(map[xi][yi] \u0026amp; bitarray[ibit]) { xtmp[indextmp] = xi; ytmp[indextmp++] = yi; map[xi][yi] -= bitarray[ibit]; } } } Pointxy pxyt[81]; int indext = 0; for(int i = 1; i \u0026lt; index; i++) { pxyt[indext].x = pxy[i].x; pxyt[indext].y = pxy[i].y; pxyt[indext].val = CountOnes(map[pxyt[indext].x][pxyt[indext].y]); indext++; } Move(pxyt, indext, board); for(int i = 0; i \u0026lt; indextmp; i++) { int xi = xtmp[i]; int yi = ytmp[i]; map[xi][yi] += bitarray[ibit]; } map[pi][pj] += bitarray[ibit]; } } } } void solveSudoku(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board) { for(int i = 0; i \u0026lt; 9; i++) { bitarray[i] = (int)pow(2.0, i); } int count = 0; for(int i = 0; i \u0026lt; 9; i++) { for(int j = 0; j \u0026lt; 9; j++) { if(board[i][j] == \u0026#39;.\u0026#39;) { map[i][j] = 511; } else { map[i][j] = bitarray[board[i][j] - \u0026#39;0\u0026#39;-1]; count++; } } } if(count \u0026lt; 17)return; Pointxy pxy[81]; int index = 0; for(int i = 0; i \u0026lt; 9; i++) { for(int j = 0; j \u0026lt; 9; j++) { if(map[i][j] == 511) { if(RefeshMap(i, j) == false)return; pxy[index].x = i; pxy[index].y = j; pxy[index++].val = CountOnes(map[i][j]); } if(CountOnes(map[i][j]) == 1) { int k = 0; for(k = 0; k \u0026lt; 9; k++) { if(map[i][j] == bitarray[k])break; } board[i][j] = k+1+\u0026#39;0\u0026#39;; } } } result = false; Move(pxy, index, board); } }; ","date":"2015-05-23T02:36:30Z","permalink":"https://blog.coinidea.com/en/p/leetcode_37sudoku-solver/","title":"[leetcode_37]Sudoku Solver"},{"content":"Deep copy of a linked list with random pointers.\nUsing two passes with a map solves this problem in O(n log n) time complexity.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 class Solution { public: RandomListNode *copyRandomList(RandomListNode *head) { int length = getRandomList(head); if(length == 0) return NULL; int index = 0; RandomListNode * headb1 = head; map\u0026lt;RandomListNode *, int\u0026gt; map_ri; map_ri.clear(); while(head != NULL) { map_ri.insert(map\u0026lt;RandomListNode *, int\u0026gt;::value_type(head, index++)); head = head-\u0026gt;next; } int *pos = new int[length]; map\u0026lt;RandomListNode *, int\u0026gt;::iterator itri; index = 0; head = headb1; while(head != NULL) { itri = map_ri.find(head-\u0026gt;random); if(itri == map_ri.end()) pos[index++] = -1; else pos[index++] = itri-\u0026gt;second; head = head-\u0026gt;next; } head = headb1; map\u0026lt;int, RandomListNode *\u0026gt; map_r; map_r.clear(); index = 0; RandomListNode *copy = new RandomListNode(head-\u0026gt;label); RandomListNode *copymove = copy; map_r.insert(map\u0026lt;int, RandomListNode *\u0026gt;::value_type(index++, copymove)); head = head-\u0026gt;next; while(head != NULL) { RandomListNode * tmp = new RandomListNode(head-\u0026gt;label); copymove-\u0026gt;next = tmp; copymove = copymove-\u0026gt;next; map_r.insert(map\u0026lt;int, RandomListNode *\u0026gt;::value_type(index++, copymove)); head = head-\u0026gt;next; } copymove = copy; index = 0; while(copymove != NULL) { map\u0026lt;int, RandomListNode *\u0026gt;::iterator it = map_r.find(pos[index++]); if(it == map_r.end()) copymove-\u0026gt;random = NULL; else copymove-\u0026gt;random = it-\u0026gt;second; copymove = copymove-\u0026gt;next; } return copy; } private: int getRandomList(RandomListNode *head) { int length = 0; while(head != NULL) { head = head-\u0026gt;next; length++; } return length; } }; ","date":"2015-05-23T02:35:14Z","permalink":"https://blog.coinidea.com/en/p/leetcode_138copy-list-with-random-pointer/","title":"[leetcode_138]Copy List with Random Pointer"},{"content":"I\u0026rsquo;m quite happy that I solved this one independently \u0026ndash; the previous two problems had really shaken my confidence. One had a test case I couldn\u0026rsquo;t pass, and the other had an approach I couldn\u0026rsquo;t figure out.\nInitially I thought of brute force: enumerate every split point, and as long as the left and right substrings are equal after sorting, it works.\nSimulate this idea and find where the left-left equal strings occur.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 int cmp(char a,char b) { return a \u0026lt; b; } class Solution { public: bool isScramble(string s1, string s2) { if(s1.length() != s2.length())return false; string s1t = s1; string s2t = s2; sort(s1.begin(),s1.end(),cmp); sort(s2.begin(),s2.end(),cmp); if(s1 != s2)return false; return checkIs(s1t,s2t) || checkIs(s2t,s1t) || checkIs(string(s1t.rbegin(),s1t.rend()),s2t) || checkIs(s2t,string(s1t.rbegin(),s1t.rend())); } private: bool checkIs(string s1,string s2) { if(s1.length() \u0026lt;= 0)return true; if(s1.length() == 1) { if(s1[0] == s2[0])return true; else return false; } int i = 0; while(i \u0026lt; s1.length()) { if(s2[i] != s1[0]) { i++; continue; } string s1b(s1,1,i); string s2b(s2,0,i); sort(s1b.begin(),s1b.end(),cmp); sort(s2b.begin(),s2b.end(),cmp); if(s1b != s2b) { i++; continue; } else break; } if(i == s1.length())return false; if(i == s1.length()-1) { string s1t = string(s1,1,i); string s2t = string(s2,0,i); return checkIs(s1t,s2t) || checkIs(s2t,s1t) || checkIs(string(s1t.rbegin(),s1t.rend()),s2t) || checkIs(s2t,string(s1t.rbegin(),s1t.rend())); } string s1e(s1,i+1); string s2e(s2,i+1); sort(s1e.begin(),s1e.end(),cmp); sort(s2e.begin(),s2e.end(),cmp); if(s1e != s2e)return false; string s1t = string(s1,1,i); string s2t = string(s2,0,i); bool flag1 = checkIs(s1t,s2t) || checkIs(s2t,s1t) || checkIs(string(s1t.rbegin(),s1t.rend()),s2t) || checkIs(s2t,string(s1t.rbegin(),s1t.rend())); s1t = string(s1,i+1); s2t = string(s2,i+1); bool flag2 = checkIs(s1t,s2t) || checkIs(s2t,s1t) || checkIs(string(s1t.rbegin(),s1t.rend()),s2t) || checkIs(s2t,string(s1t.rbegin(),s1t.rend())); return flag1 \u0026amp;\u0026amp; flag2; } }; ","date":"2015-05-23T02:33:57Z","permalink":"https://blog.coinidea.com/en/p/leetcode_87scramble-string/","title":"[leetcode_87]Scramble String"},{"content":"Find the largest rectangle area in a histogram.\nUse a stack-based approach. Always keep the stack in increasing order; if not, pop and calculate.\nReference:\nhttp://blog.csdn.net/doc_sgl/article/details/11805519\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public: int largestRectangleArea(vector\u0026lt;int\u0026gt; \u0026amp;height) { if(height.size() \u0026lt;= 0) return 0; height.push_back(-1); int max = 0x80000000; vector\u0026lt;int\u0026gt; stack; stack.clear(); stack.push_back(0); for(int i = 1; i \u0026lt; height.size(); i++) { if(height[stack[stack.size()-1]] \u0026lt;= height[i]) stack.push_back(i); else { while(stack.size() \u0026gt; 0 \u0026amp;\u0026amp; height[stack[stack.size() - 1]] \u0026gt; height[i]) { int heighttmpi = stack[stack.size()-1]; stack.pop_back(); if(stack.size() == 0) { if(height[heighttmpi] * (i-0) \u0026gt; max) max = height[heighttmpi] * (i-0); } else { if(height[heighttmpi] * (i-stack[stack.size()-1]-1) \u0026gt; max) max = height[heighttmpi] * (i-stack[stack.size()-1]-1); } } } stack.push_back(i); } return max; } }; ","date":"2015-05-23T02:32:36Z","permalink":"https://blog.coinidea.com/en/p/leetcode_84largest-rectangle-in-histogram/","title":"[leetcode_84]Largest Rectangle in Histogram"},{"content":"Sort a singly linked list.\nUsing quicksort, one particular test case timed out. Frustrating.\nLater I found that even another expert\u0026rsquo;s custom quicksort couldn\u0026rsquo;t pass that test case. So I followed his approach and wrote a heap sort instead, but the space complexity is no longer constant.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public: ListNode *sortList(ListNode *head) { if(head == NULL || head-\u0026gt;next == NULL) return head; map\u0026lt;int, vector\u0026lt;ListNode *\u0026gt;\u0026gt; map_nodes; map_nodes.clear(); while(head != NULL) { if(map_nodes.find(head-\u0026gt;val) == map_nodes.end()) { vector\u0026lt;ListNode *\u0026gt; item; item.clear(); item.push_back(head); map_nodes.insert(pair\u0026lt;int, vector\u0026lt;ListNode *\u0026gt;\u0026gt;(head-\u0026gt;val, item)); } else { map\u0026lt;int, vector\u0026lt;ListNode *\u0026gt;\u0026gt;::iterator it = map_nodes.find(head-\u0026gt;val); it-\u0026gt;second.push_back(head); } head = head-\u0026gt;next; } map\u0026lt;int, vector\u0026lt;ListNode *\u0026gt;\u0026gt;::iterator it = map_nodes.begin(); head = it-\u0026gt;second[0]; ListNode *tmp = head; for(int i = 1; i \u0026lt; it-\u0026gt;second.size(); i++) { tmp-\u0026gt;next = it-\u0026gt;second[i]; tmp = tmp-\u0026gt;next; } for(; it != map_nodes.end(); it++) { tmp-\u0026gt;next = it-\u0026gt;second[0]; tmp = tmp-\u0026gt;next; for(int i = 1; i \u0026lt; it-\u0026gt;second.size(); i++) { tmp-\u0026gt;next = it-\u0026gt;second[i]; tmp = tmp-\u0026gt;next; } } tmp-\u0026gt;next = NULL; return head; } }; ","date":"2015-05-23T02:28:03Z","permalink":"https://blog.coinidea.com/en/p/leetcode_148sort-list/","title":"[leetcode_148]Sort List"},{"content":"Find the k-th permutation of [1, 2, 3, \u0026hellip;, n].\nBrute force times out. In fact, at each digit you can eliminate a batch of candidates without searching one by one.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 class Solution { public: string getPermutation(int n, int k) { count = 0; flag = new bool[n+1]; for(int i = 1;i \u0026lt;= n;i++) { flag[i] = false; } string ans = \u0026#34;\u0026#34;; string result = \u0026#34;\u0026#34;; for(int i = 1;i \u0026lt;= n;i++) { if(result != \u0026#34;\u0026#34;) break; if(k \u0026gt; factorial(n-1) + count) { count += factorial(n-1); continue; } if(flag[i] == false) { flag[i] = true; ans.push_back(i + \u0026#39;0\u0026#39;); getPermutationStep(n, k, 1, ans); ans.erase(ans.end()-1); flag[i] = false; } } return result; } private: int count; bool *flag; string result; void getPermutationStep(int n, int k, int now, string ans) { if(result != \u0026#34;\u0026#34;) return; if(now == n) { count++; if(k \u0026lt;= count) { result = ans; } return; } for(int i = 1;i \u0026lt;= n;i++) { if(flag[i] == false) { if(now==1 \u0026amp;\u0026amp; k \u0026gt; factorial(n-now-1) + count) { count += factorial(n-now-1); continue; } flag[i] = true; ans.push_back(i + \u0026#39;0\u0026#39;); getPermutationStep(n, k, now+1, ans); ans.erase(ans.end()-1); flag[i] = false; } } } } int factorial(int x) { int ans = 1; for(int i = 1;i \u0026lt;= x;i++) { ans *= i; } return ans; } ","date":"2015-05-23T02:26:50Z","permalink":"https://blog.coinidea.com/en/p/leetcode_60permutation-sequence/","title":"[leetcode_60]Permutation Sequence"},{"content":"Rotate a singly linked list by k nodes.\nInitially got WA, then realized k needs to be taken modulo the list length.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public: ListNode *rotateRight(ListNode *head, int k) { int height = heightList(head); if(height == 0)return head; k %= height; if(height \u0026lt; k || head == NULL || head-\u0026gt;next == NULL || k == 0)return head; k = height - k; ListNode * before = head; ListNode * now = head-\u0026gt;next; k--; while(k \u0026gt; 0) { k--; before = now; now = now-\u0026gt;next; } ListNode * tmp = head; while(tmp-\u0026gt;next != NULL) { tmp = tmp-\u0026gt;next; } tmp-\u0026gt;next = head; before-\u0026gt;next = NULL; return now; } private: int heightList(ListNode * head) { int height = 0; while(head != NULL) { head = head-\u0026gt;next; height++; } return height; } }; ","date":"2015-05-23T02:25:25Z","permalink":"https://blog.coinidea.com/en/p/leetcode_61rotate-list/","title":"[leetcode_61]Rotate List"},{"content":"Given an array, find all unique quadruplets whose sum equals the target number.\nO(n^3*logn) barely passes. There should be a faster approach.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 int cmp(int a, int b) { return a \u0026lt; b; } class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; fourSum(vector\u0026lt;int\u0026gt; \u0026amp;num, int target) { sort(num.begin(), num.end(), cmp); vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; ans.clear(); if (num.size() \u0026lt;= 3) return ans; for (int i = 0; i \u0026lt; num.size() - 3; i++) { for (int j = i + 1; j \u0026lt; num.size() - 2; j++) { for (int k = j + 1; k \u0026lt; num.size() - 1; k++) { int val = target - (num[i] + num[j] + num[k]); if (val \u0026gt;= num[k + 1] \u0026amp;\u0026amp; findTarget(k + 1, num.size() - 1, val, num)) { vector\u0026lt;int\u0026gt; item; item.clear(); item.push_back(num[i]); item.push_back(num[j]); item.push_back(num[k]); item.push_back(val); if (!checkExist(ans, item)) ans.push_back(item); } } } } return ans; } private: bool checkExist(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;ans, vector\u0026lt;int\u0026gt; \u0026amp;item) { for (int i = 0; i \u0026lt; ans.size(); i++) { if (item == ans[i]) return true; } return false; } bool findTarget(int left, int right, int target, vector\u0026lt;int\u0026gt; \u0026amp;num) { if (left \u0026gt; right) return false; int mid = (left + right) / 2; if (num[mid] == target) return true; else if (num[mid] \u0026gt; target) { return findTarget(left, mid - 1, target, num); } else { return findTarget(mid + 1, right, target, num); } } }; ","date":"2015-05-23T02:24:26Z","permalink":"https://blog.coinidea.com/en/p/leetcode_184sum/","title":"[leetcode_18]4Sum"},{"content":"The third problem in the Best Time to Buy and Sell Stock series. The previous two problems allow unlimited transactions and only one transaction, respectively.\nThis problem allows two transactions.\nWith two transactions, you can split the problem at some point, turning it into two single-transaction problems. But this approach times out with O(n^2) complexity.\nAn alternative approach:\nProcess forward and backward using the single-transaction method, then store the max value at each point. This gives a linear solution.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 class Solution { public: int maxProfit(vector\u0026lt;int\u0026gt; \u0026amp;prices) { if(prices.size() \u0026lt;= 1) return 0; vector\u0026lt;int\u0026gt; dis; dis.clear(); for(int i = 0; i \u0026lt; prices.size()-1; i++) { int val = prices[i+1] - prices[i]; dis.push_back(val); } vector\u0026lt;int\u0026gt; cost; cost.clear(); if(dis[0] \u0026lt;= 0) { cost.push_back(0); } else { cost.push_back(dis[0]); } for(int i = 1; i \u0026lt; dis.size(); i++) { if(cost[i-1] + dis[i] \u0026gt;= 0) { cost.push_back(cost[i-1] + dis[i]); } else { cost.push_back(0); } } int maxnow = 0; for(int i = 0; i \u0026lt; cost.size(); i++) { if(cost[i] \u0026lt; maxnow) cost[i] = maxnow; else { maxnow = cost[i]; } } vector\u0026lt;int\u0026gt; cost_back; cost_back.clear(); if(dis[dis.size()-1] \u0026lt;= 0) { cost_back.push_back(0); } else { cost_back.push_back(dis[dis.size()-1]); } for(int i = dis.size() - 2; i \u0026gt;= 0; i--) { if(cost_back[dis.size()-2-i] + dis[i] \u0026gt;= 0) { cost_back.push_back(cost_back[dis.size()-2-i] + dis[i]); } else { cost_back.push_back(0); } } maxnow = 0; for(int i = 0; i \u0026lt; cost_back.size(); i++) { if(cost_back[i] \u0026lt; maxnow) cost_back[i] = maxnow; else { maxnow = cost_back[i]; } } int max = 0; for(int i = 0; i \u0026lt; cost.size(); i++) { if(cost.size() - 2 - i \u0026gt;= 0 \u0026amp;\u0026amp; cost.size() - 2 - i \u0026lt; cost.size()) { if(max \u0026lt; cost[i] + cost_back[cost.size()-2-i]) { max = cost[i] + cost_back[cost.size()-2-i]; } } else { if(max \u0026lt; cost[i]) max = cost[i]; } } return max; } }; ","date":"2015-05-23T02:23:19Z","permalink":"https://blog.coinidea.com/en/p/leetcode_123best-time-to-buy-and-sell-stock-iii/","title":"[leetcode_123]Best Time to Buy and Sell Stock III"},{"content":"Two nodes in a binary search tree have been swapped, and you need to restore the tree.\nI\u0026rsquo;m not sure if my approach is correct \u0026ndash; I only restored them at the value level. But the problem says not to break the structure?\nThe idea is simple: in-order traversal + linear array correction.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 class Solution { public: void recoverTree(TreeNode *root) { if(root == NULL)return ; treeArray.clear(); inOrder(root); int x,y; int flag = 0; for(int i = 0;i \u0026lt; treeArray.size();i++) { if(i == 0 \u0026amp;\u0026amp; treeArray[i] \u0026gt; treeArray[i+1] \u0026amp;\u0026amp; i \u0026lt; treeArray.size()-1) { if(flag == 0) { x = i; flag = 1; } else { y = i; } continue; } if(i == treeArray.size()-1 \u0026amp;\u0026amp; treeArray[i] \u0026lt; treeArray[i-1] \u0026amp;\u0026amp; i \u0026gt; 0) { if(flag == 0) { x = i; flag = 1; } else { y = i; } continue; } if( i \u0026gt; 0 \u0026amp;\u0026amp; i \u0026lt; treeArray.size()-1 \u0026amp;\u0026amp; treeArray[i] \u0026gt; treeArray[i-1] \u0026amp;\u0026amp; treeArray[i] \u0026gt; treeArray[i+1]) { if(flag == 0) { x = i; flag = 1; } else { y = i; } continue; } if( i \u0026gt; 0 \u0026amp;\u0026amp; i \u0026lt; treeArray.size()-1 \u0026amp;\u0026amp; treeArray[i] \u0026lt; treeArray[i-1] \u0026amp;\u0026amp; treeArray[i] \u0026lt; treeArray[i+1] ) { if(flag == 0) { x = i; flag = 1; } else { y = i; } continue; } } if(flag == 0) { for(int i = 0;i \u0026lt; treeArray.size()-1;i++) { if(treeArray[i] \u0026gt; treeArray[i+1]) { x = i; y = i+1; break; } } } queryTree(root,x,y); } private: vector\u0026lt;int\u0026gt; treeArray; void inOrder(TreeNode * root) { if(root-\u0026gt;left != NULL) inOrder(root-\u0026gt;left); treeArray.push_back(root-\u0026gt;val); if(root-\u0026gt;right != NULL) inOrder(root-\u0026gt;right); } void queryTree(TreeNode * root,int x,int y) { if(root-\u0026gt;val == treeArray[x]) { root-\u0026gt;val = treeArray[y]; } else if (root-\u0026gt;val == treeArray[y]){ root-\u0026gt;val = treeArray[x]; } if(root-\u0026gt;left != NULL) queryTree(root-\u0026gt;left,x,y); if(root-\u0026gt;right != NULL) queryTree(root-\u0026gt;right,x,y); } }; ","date":"2015-05-23T02:22:12Z","permalink":"https://blog.coinidea.com/en/p/leetcode_99recover-binary-search-tree/","title":"[leetcode_99]Recover Binary Search Tree"},{"content":"Determine whether a sentence is a palindrome: case-insensitive, ignoring non-alphanumeric characters.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public: bool isPalindrome(string s) { for(int i = 0; i \u0026lt; s.length(); i++) { if(s[i] \u0026gt;= \u0026#39;A\u0026#39; \u0026amp;\u0026amp; s[i] \u0026lt;= \u0026#39;Z\u0026#39;) { s[i] = \u0026#39;a\u0026#39; + s[i] - \u0026#39;A\u0026#39;; } } int i = 0; int j = s.length() - 1; while(i \u0026lt; j) { while(!isALetter(s[i]) \u0026amp;\u0026amp; i \u0026lt; j) i++; while(!isALetter(s[j]) \u0026amp;\u0026amp; i \u0026lt; j) j--; if(i \u0026gt;= j) break; if(s[i] != s[j]) return false; else { i++; j--; } } return true; } private: bool isALetter(char c) { if((c \u0026gt;= \u0026#39;a\u0026#39; \u0026amp;\u0026amp; c \u0026lt;= \u0026#39;z\u0026#39;) || (c \u0026gt;= \u0026#39;A\u0026#39; \u0026amp;\u0026amp; c \u0026lt;= \u0026#39;Z\u0026#39;) || (c \u0026gt;= \u0026#39;0\u0026#39; \u0026amp;\u0026amp; c \u0026lt;= \u0026#39;9\u0026#39;)) return true; else return false; } }; ","date":"2015-05-23T02:20:45Z","permalink":"https://blog.coinidea.com/en/p/leetcode_125valid-palindrome/","title":"[leetcode_125]Valid Palindrome"},{"content":"Initially I could only solve it using a map. But obviously that doesn\u0026rsquo;t meet the constant space requirement.\nReference:\nhttp://blog.unieagle.net/2012/09/20/leetcode题目：first-missing-positive/\nThe DIY hash approach is clever.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { public: int firstMissingPositive(int A[], int n) { for(int i = 0; i \u0026lt; n; i++) { if(A[i] \u0026lt;= 0) A[i] = n+2; } for(int i = 0; i \u0026lt; n; i++) { if(abs(A[i]) - 1 \u0026lt; n \u0026amp;\u0026amp; A[abs(A[i]) - 1] \u0026gt; 0) A[abs(A[i]) - 1] *= (-1); } for(int i = 1; i \u0026lt;= n; i++) { if(A[i-1] \u0026gt;= 0) return i; } return n + 1; } }; ","date":"2015-05-23T02:19:42Z","permalink":"https://blog.coinidea.com/en/p/leetcode_41first-missing-positive/","title":"[leetcode_41]First Missing Positive"},{"content":"Simulate sqrt. Note that multiplying two ints may cause overflow.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public: int sqrt(int x) { //x \u0026gt;= 0 0 ~ x/2 if(x \u0026lt;= 0)return 0; int left = 1; int right = x / 2; bsearch(left, right, x); return ans; } private: int ans; void bsearch(int left, int right, int x) { if(left \u0026gt;= right) { ans = left; if(1.0 * ans * ans \u0026gt; x) ans--; return; } int mid = (left + right) / 2; if(1.0 * mid * mid == x) { ans = mid; return; } else if(1.0 * mid * mid \u0026gt; x) { bsearch(left, mid-1, x); } else if(1.0 * mid * mid \u0026lt; x) { bsearch(mid+1, right, x); } } }; ","date":"2015-05-23T02:18:28Z","permalink":"https://blog.coinidea.com/en/p/leetcode_69sqrtx/","title":"[leetcode_69]Sqrt(x)"},{"content":"K-way merge sort. Watch out for various boundary conditions: such as NULL pointers or empty vectors.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 class Solution { public: ListNode *mergeKLists(vector\u0026lt;ListNode *\u0026gt; \u0026amp;lists) { if(lists.size() \u0026lt;= 0) return NULL; while(lists.size() \u0026gt; 1) { vector\u0026lt;ListNode *\u0026gt;lists_tmp; lists_tmp.clear(); ListNode * tmp; int i = 0; while (true) { tmp = merge2Lists(lists[2*i],lists[2*i+1]); lists_tmp.push_back(tmp); i++; if(2*i+1 == lists.size()) { lists_tmp.push_back(lists[2*i]); break; } if(2*i+1 \u0026gt; lists.size()) { break; } } lists.clear(); lists = lists_tmp; } return lists[0]; } private: ListNode *merge2Lists(ListNode * list1,ListNode * list2) { ListNode * list = NULL; ListNode * list_c = NULL; while(list1 != NULL \u0026amp;\u0026amp; list2 != NULL) { if(list1-\u0026gt;val \u0026lt; list2-\u0026gt;val) { if(list == NULL) { list = list1; list_c = list; } else { list_c-\u0026gt;next = list1; list_c = list_c-\u0026gt;next; } list1 = list1-\u0026gt;next; } else { if(list == NULL) { list = list2; list_c = list; } else { list_c-\u0026gt;next = list2; list_c = list_c-\u0026gt;next; } list2 = list2-\u0026gt;next; } } while(list1!=NULL) { if(list_c == NULL) { list_c = list1; list = list_c; list1 = list1-\u0026gt;next; continue; } list_c-\u0026gt;next = list1; list_c= list_c-\u0026gt;next; list1 = list1-\u0026gt;next; } while(list2!=NULL) { if(list_c == NULL) { list_c = list2; list = list_c; list2 = list2-\u0026gt;next; continue; } list_c-\u0026gt;next = list2; list_c= list_c-\u0026gt;next; list2 = list2-\u0026gt;next; } if(list_c != NULL)list_c-\u0026gt;next = NULL; return list; } }; ","date":"2015-05-23T02:17:22Z","permalink":"https://blog.coinidea.com/en/p/leetcode_23merge-k-sorted-lists/","title":"[leetcode_23]Merge k Sorted Lists"},{"content":"Keep expanding the farthest reachable position.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public: int jump(int A[], int n) { if (n \u0026lt;= 1) return 0; int min = -1; int max = 0; int maxstep = 0; int count = 0; while (true) { count++; for (int i = min + 1; i \u0026lt;= max; i++) { if (i + A[i] \u0026gt;= n - 1) { return count; } if (i + A[i] \u0026gt;= maxstep) maxstep = i + A[i]; } min = max; max = maxstep; } return -1; } }; ","date":"2015-05-23T02:16:14Z","permalink":"https://blog.coinidea.com/en/p/leetcode_45jump-game-ii/","title":"[leetcode_45]Jump Game II"},{"content":"Given multiple strings, find the groups of strings that are anagrams of each other.\nAnagrams: eat ate eta\nThe approach for this problem is: sort, then sort again.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 int cmp(int a, int b) { return a \u0026lt; b; } struct Item { int index; string val; }; int cmpitem(Item a, Item b) { return a.val \u0026lt; b.val; } class Solution { public: vector\u0026lt;string\u0026gt; anagrams(vector\u0026lt;string\u0026gt; \u0026amp;strs) { vector\u0026lt;Item\u0026gt; strs_cpy; strs_cpy.clear(); for(int i = 0; i \u0026lt; strs.size(); i++) { Item item; item.index = i; item.val = strs[i]; sort(item.val.begin(), item.val.end(), cmp); strs_cpy.push_back(item); } sort(strs_cpy.begin(), strs_cpy.end(), cmpitem); vector\u0026lt;string\u0026gt; ans; ans.clear(); int index = 0; for(int i = 1; i \u0026lt; strs_cpy.size(); i++) { if(strs_cpy[i].val == strs_cpy[index].val) { if(i - index == 1) { ans.push_back(strs[strs_cpy[index].index]); } ans.push_back(strs[strs_cpy[i].index]); } else { index = i; } } return ans; } }; ","date":"2015-05-23T02:14:55Z","permalink":"https://blog.coinidea.com/en/p/leetcode_49anagrams/","title":"[leetcode_49]Anagrams"},{"content":"Find a series of numbers in an array that sum up to the target.\nSearch with pruning. Pay attention to deduplication and ascending order.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 int cmp(int a,int b) { return a \u0026lt; b; } class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;ans; vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; combinationSum2(vector\u0026lt;int\u0026gt; \u0026amp;num, int target) { ans.clear(); sort(num.begin(),num.end(),cmp); vector\u0026lt;int\u0026gt; seq; seq.clear(); addStep(num,0,0,target,seq); return ans; } private: bool isSeqInAns(vector\u0026lt;int\u0026gt; \u0026amp;seq) { for(int i = 0;i \u0026lt; ans.size();i++) { if(ans[i] == seq)return false; } return true; } void addStep(vector\u0026lt;int\u0026gt; \u0026amp;num,int sum,int k,int target,vector\u0026lt;int\u0026gt; \u0026amp;seq) { if(sum == target) { if(isSeqInAns(seq)) ans.push_back(seq); return; } if(k \u0026gt;= num.size()) { return ; } if(sum + num[k] \u0026lt;= target) { seq.push_back(num[k]); addStep(num,sum+num[k],k+1,target,seq); seq.pop_back(); } addStep(num,sum,k+1,target,seq); } }; ","date":"2015-05-22T12:13:52Z","permalink":"https://blog.coinidea.com/en/p/leetcode_140-combination-sum-ii/","title":"[leetcode_140] Combination Sum II"},{"content":"Given strings S and T, count how many distinct subsequences of S equal T (i.e., how many ways can you delete characters from S to form T).\nInitially, brute-force search timed out. I hadn\u0026rsquo;t mastered the right technique.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 struct PointS { int index; int count; }; class Solution { public: int ans; vector\u0026lt;PointS\u0026gt; seq; int numDistinct(string S, string T) { ans = 0; if(T.length() \u0026lt;= 0)return ans; seq.clear(); for(int i = 0;i \u0026lt; S.length();i++) { if(S[i] == T[T.length()-1]) { PointS item; item.index = i; item.count = 1; seq.push_back(item); } } matchStep(T.length() - 2,S,T,seq); return ans; } private: void matchStep (int now,string S,string T,vector\u0026lt;PointS\u0026gt;\u0026amp; seq) { if(now == -1) { for(int i = 0;i \u0026lt; seq.size();i++) { PointS item = seq[i]; ans += item.count; } return ; } vector\u0026lt;PointS\u0026gt; seq_c; seq_c.clear(); int i = 0; int bottom = 0; int sum = 0; for(int i = 0;i \u0026lt; seq.size();i++) sum += seq[i].count; while(i \u0026lt; seq.size()) { for(int j = bottom;j \u0026lt; seq[i].index;j++) { if(S[j] == T[now]) { PointS item; item.index = j; item.count = sum; seq_c.push_back(item); } } bottom = seq[i].index; sum -= seq[i].count; i++; } seq.clear(); matchStep (now - 1,S,T,seq_c); } }; ","date":"2015-05-22T12:11:50Z","permalink":"https://blog.coinidea.com/en/p/leetcode_115-distinct-subsequences/","title":"[leetcode_115] Distinct Subsequences"},{"content":"100 problems done! A small milestone to celebrate.\nFirst, check whether a feasible solution exists.\nThen start from each node and find the first one that can reach the end.\nGot AC. I believe the approach is correct, but I\u0026rsquo;m not 100% certain.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public: int canCompleteCircuit(vector\u0026lt;int\u0026gt; \u0026amp;gas, vector\u0026lt;int\u0026gt; \u0026amp;cost) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. int ans = -1; int sum = 0; for(int i = 0;i \u0026lt; gas.size();i++) { sum += gas[i]; sum -= cost[i]; } if(sum \u0026lt; 0)return ans; int now = 0; int i = 0; ans = 0; while(i \u0026lt; gas.size()) { now += gas[i] - cost[i]; if(now \u0026lt; 0) { i++; now = 0; ans = i; } else i++; } return ans; } }; ","date":"2015-05-22T12:10:46Z","permalink":"https://blog.coinidea.com/en/p/leetcode_134-gas-station/","title":"[leetcode_134] Gas Station"},{"content":"Singly linked list — reverse every k nodes. If the remaining length is less than k, do not reverse.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Solution { public: int len; ListNode *reverseKGroup(ListNode *head, int k) { len = getLength(head); if(len \u0026lt; k || head == NULL || k \u0026lt;= 1) { return head; } ListNode ** tmp = new ListNode *[2]; tmp = reverseKStep(head,k); len -= k; head = tmp[0]; ListNode * beforebackup = tmp[1]; while(len \u0026gt;= k) { tmp = reverseKStep(beforebackup-\u0026gt;next,k); len -= k; beforebackup-\u0026gt;next = tmp[0]; beforebackup = tmp[1]; } return head; } private: // Returns two pointers: the first is the head, the second is the last node ListNode **reverseKStep(ListNode *before,int k) { ListNode * beforebackup = before; ListNode * now = before-\u0026gt;next; int count = 1; while(now != NULL \u0026amp;\u0026amp; count \u0026lt; k) { count++; ListNode * next = now-\u0026gt;next; now-\u0026gt;next = before; before = now; now = next; } beforebackup-\u0026gt;next = now; ListNode ** ans = new ListNode *[2]; ans[0] = before; ans[1] = beforebackup; return ans; } int getLength(ListNode *head) { int lentmp = 0; while(head != NULL) { head = head-\u0026gt;next; lentmp++; } return lentmp; } }; ","date":"2015-05-22T12:09:33Z","permalink":"https://blog.coinidea.com/en/p/leetcode_25-reverse-nodes-in-k-group/","title":"[leetcode_25] Reverse Nodes in k-Group"},{"content":"This is a dynamic programming problem. Reference:\nhttp://blog.csdn.net/abcjennifer/article/details/7735272\nBy the time I got to this problem, I honestly felt like I couldn\u0026rsquo;t keep going. The problem itself isn\u0026rsquo;t that complex, but I felt like my brain was too slow.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { public: int minDistance(string word1, string word2) { len1 = word1.length(); len2 = word2.length(); initdptable(); for(int i = 1;i \u0026lt;= len1;i++) { for(int j = 1;j \u0026lt;= len2;j++) { dpTable[i][j] = getMin(word1[i-1] == word2[j-1] ? dpTable[i-1][j-1]:dpTable[i-1][j-1] + 1,dpTable[i-1][j]+1,dpTable[i][j-1]+1); } } //displaydptable(); return dpTable[len1][len2]; } private: int **dpTable; int len1,len2; int getMin(int a,int b,int c) { int min = a; if(min \u0026gt; b)min = b; if(min \u0026gt; c)min = c; return min; } void initdptable() { dpTable = new int *[len1+1]; for(int i = 0;i \u0026lt;= len1;i++) { dpTable[i] = new int[len2+1]; } for(int i = 0;i \u0026lt;= len1;i++) { dpTable[i][0] = i; } for(int i = 0;i \u0026lt;= len2;i++) { dpTable[0][i] = i; } } void displaydptable() { for(int i = 0;i \u0026lt;= len1;i++) { for(int j = 0;j \u0026lt;= len2;j++) { cout \u0026lt;\u0026lt; dpTable[i][j] \u0026lt;\u0026lt; \u0026#34; \u0026#34;; } cout \u0026lt;\u0026lt; endl; } } }; ","date":"2015-05-22T12:08:23Z","permalink":"https://blog.coinidea.com/en/p/leetcode_72edit-distance/","title":"[leetcode_72]Edit Distance"},{"content":"Find all partitions such that every substring in each partition is a palindrome.\nThe basic approach is:\nSearch At each position, either split or don\u0026rsquo;t. Once a split is made, check whether the newly formed substring is a palindrome. If yes, continue searching; if not, the split is invalid. When the end is reached, record the result. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 class Solution { public: vector\u0026lt;vector\u0026lt;string\u0026gt;\u0026gt; ans; vector\u0026lt;vector\u0026lt;string\u0026gt;\u0026gt; partition(string s) { ans.clear(); if(s.length() \u0026lt;= 0) return ans; bool *flag = new bool[s.length()+1]; for(int i = 0; i \u0026lt;= s.length(); i++) flag[i] = false; flag[0] = true; PartitionStep(s, 1, flag); return ans; } private: void PartitionStep(string s, int step, bool *flag) { if(step == s.length()) { int i; flag[step] = true; for(i = step-1; i \u0026gt;= 0; i--) { if(flag[i] == true) break; } if(IsPalindrome(s, i, step-1)) { GenAnsItem(s, flag); } flag[step] = false; return; } flag[step] = true; int i; for(i = step-1; i \u0026gt;= 0; i--) { if(flag[i] == true) break; } if(IsPalindrome(s, i, step-1)) { PartitionStep(s, step+1, flag); } flag[step] = false; PartitionStep(s, step+1, flag); } bool IsPalindrome(string s, int i, int j) { while(i \u0026lt; j) { if(s[i] != s[j]) return false; i++; j--; } return true; } void GenAnsItem(string s, bool *flag) { vector\u0026lt;string\u0026gt; item; item.clear(); int i = 1; int before = 0; while(i \u0026lt;= s.length()) { if(flag[i] == true) { string tmp = \u0026#34;\u0026#34;; for(int j = before; j \u0026lt; i; j++) { tmp.push_back(s[j]); } item.push_back(tmp); before = i; } i++; } ans.push_back(item); } }; ","date":"2015-05-22T12:07:00Z","permalink":"https://blog.coinidea.com/en/p/leetcode_131palindrome-partitioning/","title":"[leetcode_131]Palindrome Partitioning"},{"content":"Remove all nodes from a sorted singly linked list that have duplicate values.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public: ListNode *deleteDuplicates(ListNode *head) { while(head != NULL \u0026amp;\u0026amp; head-\u0026gt;next != NULL \u0026amp;\u0026amp; head-\u0026gt;val == head-\u0026gt;next-\u0026gt;val) { while(head != NULL \u0026amp;\u0026amp; head-\u0026gt;next != NULL \u0026amp;\u0026amp; head-\u0026gt;val == head-\u0026gt;next-\u0026gt;val) { head = head-\u0026gt;next; } if(head != NULL) { head = head-\u0026gt;next; } } if(head == NULL || head-\u0026gt;next == NULL)return head; ListNode * now = head-\u0026gt;next; ListNode * node = head; while(now != NULL \u0026amp;\u0026amp; now-\u0026gt;next != NULL){ while(now != NULL \u0026amp;\u0026amp; now-\u0026gt;next != NULL \u0026amp;\u0026amp; now-\u0026gt;val == now-\u0026gt;next-\u0026gt;val) { while(now != NULL \u0026amp;\u0026amp; now-\u0026gt;next != NULL \u0026amp;\u0026amp; now-\u0026gt;val == now-\u0026gt;next-\u0026gt;val) { now = now-\u0026gt;next; } if(now != NULL) { now = now-\u0026gt;next; } } node-\u0026gt;next = now; node = node-\u0026gt;next; if(node == NULL)break; now = node-\u0026gt;next; } return head; } }; ","date":"2015-05-22T12:05:39Z","permalink":"https://blog.coinidea.com/en/p/leetcode_82remove-duplicates-from-sorted-list-ii/","title":"[leetcode_82]Remove Duplicates from Sorted List II"},{"content":"Given a digit string, return all possible letter combinations that the digits could represent on a phone keypad.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public: vector\u0026lt;string\u0026gt; ans; vector\u0026lt;string\u0026gt; letterCombinations(string digits) { // Note: The Solution object is instantiated only once and is reused by each test case. vector\u0026lt;string\u0026gt; map = GenMap(); ans.clear(); string item = \u0026#34;\u0026#34;; letterCStep(digits, 0, item, map); return ans; } private: void letterCStep(string digits, int step, string item, vector\u0026lt;string\u0026gt;\u0026amp; map) { if (step \u0026gt;= digits.length()) { ans.push_back(item); return; } else { int index = digits[step] - \u0026#39;0\u0026#39;; for (int i = 0; i \u0026lt; map[index].size(); i++) { item.push_back(map[index][i]); letterCStep(digits, step + 1, item, map); item.erase(item.end() - 1); } } } vector\u0026lt;string\u0026gt; GenMap() { vector\u0026lt;string\u0026gt; map; map.clear(); map.push_back(\u0026#34; \u0026#34;); map.push_back(\u0026#34;\u0026#34;); map.push_back(\u0026#34;abc\u0026#34;); map.push_back(\u0026#34;def\u0026#34;); map.push_back(\u0026#34;ghi\u0026#34;); map.push_back(\u0026#34;jkl\u0026#34;); map.push_back(\u0026#34;mno\u0026#34;); map.push_back(\u0026#34;pqrs\u0026#34;); map.push_back(\u0026#34;tuv\u0026#34;); map.push_back(\u0026#34;wxyz\u0026#34;); return map; } }; ","date":"2015-05-22T12:04:25Z","permalink":"https://blog.coinidea.com/en/p/leetcode_17letter-combinations-of-a-phone-number/","title":"[leetcode_17]Letter Combinations of a Phone Number"},{"content":"Construct a binary tree from preorder and inorder traversal sequences, guaranteed no duplicate values. Be careful not to exceed memory limits.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public: TreeNode *buildTree(vector\u0026lt;int\u0026gt; \u0026amp;preorder, vector\u0026lt;int\u0026gt; \u0026amp;inorder) { // Note: The Solution object is instantiated only once and is reused by each test case. if(preorder.size() \u0026lt;= 0 || inorder.size() \u0026lt;= 0) return NULL; TreeNode * root = buildTreeStep(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1); return root; } private: TreeNode *buildTreeStep(vector\u0026lt;int\u0026gt; \u0026amp;preorder,int prea,int preb, vector\u0026lt;int\u0026gt; \u0026amp;inorder,int ina,int inb) { if(prea \u0026gt; preb || ina \u0026gt; inb) return NULL; int root = preorder[prea]; int i; for(i = ina;i \u0026lt;= inb;i++) { if(inorder[i] == root) { break; } } //inorderleft:ina,i-1 //inorderright,i+1,inb //preorderleft:prea+1,prea+1+(i-1)-ina //preorderright:prea+(i-1)-ina+1,preb TreeNode * node = new TreeNode(root); node-\u0026gt;left = buildTreeStep(preorder,prea+1,prea+1+(i-1)-ina,inorder,ina,i-1); node-\u0026gt;right = buildTreeStep(preorder,prea+1+(i-1)-ina+1,preb,inorder,i+1,inb); return node; } }; ","date":"2015-05-22T12:03:11Z","permalink":"https://blog.coinidea.com/en/p/leetcode_106construct-binary-tree-from-preorder-and-inorder-traversal/","title":"[leetcode_106]Construct Binary Tree from Preorder and Inorder Traversal"},{"content":"Construct a binary tree from inorder and postorder traversal sequences, guaranteed no duplicate values. Be careful not to exceed memory limits.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public: TreeNode *buildTree(vector\u0026lt;int\u0026gt; \u0026amp;inorder, vector\u0026lt;int\u0026gt; \u0026amp;postorder) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. if(inorder.size() \u0026lt;= 0 || postorder.size() \u0026lt;= 0) return NULL; TreeNode * root = buildTreeStep(inorder,0,inorder.size()-1,postorder,0,postorder.size()-1); return root; } private: TreeNode *buildTreeStep(vector\u0026lt;int\u0026gt; \u0026amp;inorder,int ina,int inb,vector\u0026lt;int\u0026gt;\u0026amp;postorder,int poa,int pob) { if(ina \u0026gt; inb || poa \u0026gt; pob) return NULL; int root = postorder[pob]; int i; for(i = ina;i \u0026lt;= inb;i++) { if(inorder[i] == root)break; } //inleft: ina i-1 //inright:i+1 inb //poleft:poa,(i-1) - ina + poa //poright:(i-1) - ina + poa + 1,pob-1 TreeNode * node = new TreeNode(root); node-\u0026gt;left = buildTreeStep(inorder,ina,i-1,postorder,poa,(i-1)-ina+poa); node-\u0026gt;right = buildTreeStep(inorder,i+1,inb,postorder,(i-1) - ina+poa+1,pob-1); return node;\u0026lt;br /\u0026gt; } }; ","date":"2015-05-22T12:01:32Z","permalink":"https://blog.coinidea.com/en/p/leetcode_106construct-binary-tree-from-inorder-and-postorder-traversal/","title":"[leetcode_106]Construct Binary Tree from Inorder and Postorder Traversal"},{"content":"This problem was quite frustrating.\nAt first I misunderstood the problem and thought it was asking whether a Sudoku puzzle has a valid solution \u0026ndash; enumeration? Brute force.\nI wrote a version using set collections that kept timing out:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 struct PointOfBoard { set\u0026lt;int\u0026gt;set_p; bool IsExist; int val; PointOfBoard():IsExist(false),val(-1){set_p.clear();} }; class Solution { public: PointOfBoard POB[9][9]; int x[81]; int y[81]; int index; bool result; int GetRegionOfBoard(int x,int y) { if(x\u0026gt;= 0 \u0026amp;\u0026amp; x \u0026lt; 3) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 0; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 1; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 2; } if(x \u0026gt;= 3 \u0026amp;\u0026amp; x \u0026lt; 6) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 3; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 4; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 5; } if(x \u0026gt;= 6 \u0026amp;\u0026amp; x \u0026lt; 9) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 6; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 7; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 8; } } bool GetSetOfPOB(int x,int y){ set\u0026lt;int\u0026gt;set_tmp; set_tmp.clear(); for(int i = 0;i \u0026lt; 9;i++) { if(POB[x][i].IsExist) { int val = POB[x][i].val; if(set_tmp.find(val) == set_tmp.end()) set_tmp.insert(val); } if(POB[i][y].IsExist) { int val = POB[i][y].val; if(set_tmp.find(val) == set_tmp.end()) set_tmp.insert(val); } } int region = GetRegionOfBoard(x,y); int x_r = (region / 3 + 1)*3; int y_r = (region % 3 + 1)*3; for(int i = x_r-3;i \u0026lt; x_r;i++) { for(int j = y_r-3;j \u0026lt; y_r;j++) { if(POB[i][j].IsExist) { int val = POB[i][j].val; if(set_tmp.find(val) != set_tmp.end()) set_tmp.insert(val); } } } if(set_tmp.size() == 9)return false; set\u0026lt;int\u0026gt;::iterator it; for(int i = 1;i \u0026lt;= 9;i++) { if(set_tmp.find(i) == set_tmp.end())POB[x][y].set_p.insert(i); } if(POB[x][y].set_p.size() \u0026lt;= 0)return false; return true; } void Move(int step) { if(step \u0026gt;= index) { result = true; return; } else { if(result == true)return; int pi = x[step]; int pj = y[step]; set\u0026lt;int\u0026gt;::iterator it; for(it = POB[pi][pj].set_p.begin();it != POB[pi][pj].set_p.end();it++) { if(result == true)return; int val = (int)(*it); POB[pi][pj].val = val; int xtmp[81]; int ytmp[81]; int indextmp = 0; for(int i = step+1;i \u0026lt; index;i++) { int xi = x[i]; int yi = y[i]; if(xi == pi || yi == pj || GetRegionOfBoard(xi,yi) == GetRegionOfBoard(pi,pj)) { if(POB[xi][yi].set_p.find(val) != POB[xi][yi].set_p.end()) { xtmp[indextmp] = xi; ytmp[indextmp++] = yi; POB[xi][yi].set_p.erase(val); } } } Move(step+1); for(int i = 0;i \u0026lt; indextmp;i++) { int xi = xtmp[i]; int yi = ytmp[i]; POB[xi][yi].set_p.insert(val); } POB[pi][pj].val = -1; } } } bool isValidSudoku(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board) { for(int i = 0;i \u0026lt; 9;i++) { for(int j = 0;j \u0026lt; 9;j++) { if(board[i][j] == \u0026#39;.\u0026#39;) { POB[i][j].IsExist = false; } else { POB[i][j].IsExist = true; POB[i][j].val = board[i][j] - \u0026#39;0\u0026#39;; } } } for(int i = 0;i \u0026lt; 9;i++) { for(int j = 0;j \u0026lt; 9;j++) { if(POB[i][j].IsExist == false) { if(GetSetOfPOB(i,j) == false)return false; } } } index = 0; for(int i = 0;i \u0026lt; 9;i++) { for(int j = 0;j \u0026lt; 9;j++) { if(POB[i][j].IsExist == false) { x[index] = i; y[index++] = j; } } } result = false; Move(0); return result; } }; Later I saw someone else\u0026rsquo;s code using binary int representation, so I wrote another version:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 struct Pointxy { int x; int y; int val; }; int cmp(Pointxy a,Pointxy b) { return a.val \u0026lt; b.val; } class Solution { public: int bitarray[9]; int map[9][9]; bool result; int CountOnes(int v) { int number = 0; while(v) { v \u0026amp;= (v-1); number++; } return number; } int GetRegionOfBoard(int x,int y) { if(x\u0026gt;= 0 \u0026amp;\u0026amp; x \u0026lt; 3) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 0; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 1; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 2; } if(x \u0026gt;= 3 \u0026amp;\u0026amp; x \u0026lt; 6) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 3; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 4; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 5; } if(x \u0026gt;= 6 \u0026amp;\u0026amp; x \u0026lt; 9) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 6; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 7; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 8; } } bool RefeshMap(int x,int y){ int set_tmp = 0; for(int i = 0;i \u0026lt; 9;i++) { if(CountOnes(map[x][i]) == 1) { set_tmp = set_tmp | map[x][i]; } if(CountOnes(map[i][y]) == 1) { set_tmp = set_tmp | map[x][i]; } } int region = GetRegionOfBoard(x,y); int x_r = (region / 3 + 1)*3; int y_r = (region % 3 + 1)*3; for(int i = x_r-3;i \u0026lt; x_r;i++) { for(int j = y_r-3;j \u0026lt; y_r;j++) { if(CountOnes(map[i][j]) == 1) { set_tmp = set_tmp | map[i][j]; } } } if(set_tmp == 511)return false; map[x][y] = 511 - set_tmp; return true; } void Move(Pointxy pxy[81],int index) { if(result == true)return; if(index \u0026lt;= 0) { result = true; return; } else { sort(pxy,pxy+index,cmp); int pi = pxy[0].x; int pj = pxy[0].y; for(int ibit = 0;ibit \u0026lt; 9;ibit++) { if(result == true)return; if(map[pi][pj] \u0026amp; bitarray[ibit]) { map[pi][pj] -= bitarray[ibit]; int xtmp[81]; int ytmp[81]; int indextmp = 0; for(int i = 1;i \u0026lt; index;i++) { int xi = pxy[i].x; int yi = pxy[i].y; if(xi == pi || yi == pj || GetRegionOfBoard(xi,yi) == GetRegionOfBoard(pi,pj)) { if(map[xi][yi] \u0026amp; bitarray[ibit]) { xtmp[indextmp] = xi; ytmp[indextmp++] = yi; map[xi][yi] -= bitarray[ibit]; } } } Pointxy pxyt[81]; int indext = 0; for(int i = 1;i \u0026lt; index;i++) { pxyt[indext].x = pxy[i].x; pxyt[indext].y = pxy[i].y; pxyt[indext++].val = CountOnes(map[pxyt[indext].x][pxyt[indext].y]); } Move(pxyt,indext); for(int i = 0;i \u0026lt; indextmp;i++) { int xi = xtmp[i]; int yi = ytmp[i]; map[xi][yi] += bitarray[ibit]; } map[pi][pj] += bitarray[ibit]; } } } } bool isValidSudoku(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board) { for(int i = 0;i \u0026lt; 9;i++) { bitarray[i] = (int)pow(2.0,i); } int count = 0; for(int i = 0;i \u0026lt; 9;i++) { for(int j = 0;j \u0026lt; 9;j++) { if(board[i][j] == \u0026#39;.\u0026#39;) { map[i][j] = 511; } else { map[i][j] = bitarray[board[i][j] - \u0026#39;0\u0026#39;-1]; count++; } } } if(count \u0026lt; 17)return false; for(int i = 0;i \u0026lt; 9;i++) { for(int j = 0;j \u0026lt; 9;j++) { if(map[i][j] == 511) { if(RefeshMap(i,j) == false)return false; } } } Pointxy pxy[81]; int index = 0; for(int i = 0;i \u0026lt; 9;i++) { for(int j = 0;j \u0026lt; 9;j++) { if(CountOnes(map[i][j]) != 1) { pxy[index].x = i; pxy[index].y = j; pxy[index].val = CountOnes(map[i][j]); } } } result = false; Move(pxy,index); return result; } }; WA??? That doesn\u0026rsquo;t make sense???\nThe final WA was on a case that was obviously unsolvable.\nWith no other option, I looked at other people\u0026rsquo;s code. Turns out the problem only asks to validate whether the current state of the Sudoku board satisfies the rules \u0026ndash; the problem is so much simpler!\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 class Solution { public: int bitarray[9]; int map[9][9]; bool result; int GetRegionOfBoard(int x,int y) { if(x\u0026gt;= 0 \u0026amp;\u0026amp; x \u0026lt; 3) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 0; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 1; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 2; } if(x \u0026gt;= 3 \u0026amp;\u0026amp; x \u0026lt; 6) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 3; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 4; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 5; } if(x \u0026gt;= 6 \u0026amp;\u0026amp; x \u0026lt; 9) { if(y \u0026gt;= 0 \u0026amp;\u0026amp; y \u0026lt; 3)return 6; if(y \u0026gt;= 3 \u0026amp;\u0026amp; y \u0026lt; 6)return 7; if(y \u0026gt;= 6 \u0026amp;\u0026amp; y \u0026lt; 9)return 8; } } bool CheckRows() { for(int i = 0;i \u0026lt; 9;i++) { int tmp = 0; for(int j = 0;j \u0026lt; 9;j++) { if(tmp \u0026amp; map[i][j])return false; tmp |= map[i][j]; } } return true; } bool CheckCols() { for(int j = 0;j \u0026lt; 9;j++) { int tmp = 0; for(int i = 0;i \u0026lt; 9;i++) { if(tmp \u0026amp; map[i][j])return false; tmp |= map[i][j]; } } return true; } bool CheckRegion() { for(int region = 0;region \u0026lt; 9;region++) { int x_r = (region / 3 + 1)*3; int y_r = (region % 3 + 1)*3; int tmp = 0; for(int i = x_r-3;i \u0026lt; x_r;i++) { for(int j = y_r-3;j \u0026lt; y_r;j++) { if(tmp \u0026amp; map[i][j])return false; tmp = tmp | map[i][j]; } } } return true; } bool isValidSudoku(vector\u0026lt;vector\u0026lt;char\u0026gt;\u0026gt; \u0026amp;board) { for(int i = 0;i \u0026lt; 9;i++) { bitarray[i] = (int)pow(2.0,i); } for(int i = 0;i \u0026lt; 9;i++) { for(int j = 0;j \u0026lt; 9;j++) { if(board[i][j] == \u0026#39;.\u0026#39;) { map[i][j] = 0; } else { map[i][j] = bitarray[board[i][j] - \u0026#39;0\u0026#39;-1]; } } } return CheckRows() \u0026amp;\u0026amp; CheckCols() \u0026amp;\u0026amp; CheckRegion(); } }; ","date":"2015-05-22T11:59:32Z","permalink":"https://blog.coinidea.com/en/p/leetcode_36valid-sudoku/","title":"[leetcode_36]Valid Sudoku"},{"content":"Given a singly linked list, reverse the nodes from position m to n. Do not allocate extra space.\nInitially I misread the problem and thought it was about swapping two nodes at positions m and n, which resulted in WA.\nHowever, I realized that swapping is actually a step in the reversal process, so I made a few modifications to the code and got AC. Pay special attention to the cases where m=1 and n-m=1.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 class Solution { public: ListNode *reverseBetween(ListNode *head, int m, int n) { int length = GetLengthListNode(head); if(length \u0026lt;= 0 || m \u0026gt;= n || length \u0026lt; n) return head; while(m \u0026lt; n) { head = reverseBetweenStep(head,m,n); m++; n--; } return head; } private: ListNode *reverseBetweenStep(ListNode *head, int m, int n) { if(n-m == 1) { if(m == 1) { ListNode * mlistNode = head; ListNode * nlistNode = GetListNodeFromPos(head,n); ListNode * ntmpnext = nlistNode-\u0026gt;next; nlistNode-\u0026gt;next = mlistNode; mlistNode-\u0026gt;next = ntmpnext; return nlistNode; } else { ListNode * beforem = GetListNodeFromPos(head,m-1); ListNode * mlistNode = GetListNodeFromPos(head,m); ListNode * nlistNode = GetListNodeFromPos(head,n); ListNode * ntmpnext = nlistNode-\u0026gt;next; nlistNode-\u0026gt;next = mlistNode; mlistNode-\u0026gt;next = ntmpnext; beforem-\u0026gt;next = nlistNode; return head;\u0026lt;br /\u0026gt; } } if(m == 1) { ListNode * mlistNode = head; ListNode * beforen = GetListNodeFromPos(head,n-1); ListNode * nlistNode = GetListNodeFromPos(head,n); ListNode * ntmpnext = nlistNode-\u0026gt;next; nlistNode-\u0026gt;next = mlistNode-\u0026gt;next; mlistNode-\u0026gt;next = ntmpnext; beforen-\u0026gt;next = mlistNode; return nlistNode; } else { ListNode * beforem = GetListNodeFromPos(head,m-1); ListNode * mlistNode = GetListNodeFromPos(head,m); ListNode * beforen = GetListNodeFromPos(head,n-1); ListNode * nlistNode = GetListNodeFromPos(head,n); ListNode * mtmpnext = mlistNode-\u0026gt;next; ListNode * ntmpnext = nlistNode-\u0026gt;next; nlistNode-\u0026gt;next = mlistNode-\u0026gt;next; mlistNode-\u0026gt;next = ntmpnext; beforen-\u0026gt;next = mlistNode; beforem-\u0026gt;next = nlistNode; return head; } } }; ListNode * GetListNodeFromPos(ListNode *head,int pos) { pos--; while(pos--) { head = head-\u0026gt;next; } return head; } int GetLengthListNode(ListNode *listNode) { int Length = 0; while(listNode != NULL) { listNode = listNode-\u0026gt;next; Length++; } return Length; }; ","date":"2015-05-22T11:57:25Z","permalink":"https://blog.coinidea.com/en/p/leetcode_92reverse-linked-list-ii/","title":"[leetcode_92]Reverse Linked List II"},{"content":"90 problems done \u0026ndash; it really hasn\u0026rsquo;t been easy.\nBinary addition of two strings. Use an int to store the carry.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public: string addBinary(string a, string b) { string ans = \u0026#34;\u0026#34;; int lenMin = a.length() \u0026lt; b.length()?a.length():b.length(); int inbit = 0; for(int i = 0;i \u0026lt; lenMin;i++) { int aVal = a[a.length()-1-i] - \u0026#39;0\u0026#39;; int bVal = b[b.length()-1-i] - \u0026#39;0\u0026#39;; int sum = inbit + aVal + bVal; inbit = sum / 2; ans.push_back(sum%2 + \u0026#39;0\u0026#39;); } if(a.length() \u0026gt; b.length()) { for(int i = lenMin;i \u0026lt; a.length();i++) { int Val = a[a.length()-1-i] - \u0026#39;0\u0026#39; + inbit; inbit = Val / 2; ans.push_back(Val%2 + \u0026#39;0\u0026#39;); } } else { for(int i = lenMin;i \u0026lt; b.length();i++) { int Val = b[b.length()-1-i] - \u0026#39;0\u0026#39; + inbit; inbit = Val / 2; ans.push_back(Val%2 + \u0026#39;0\u0026#39;); } } if(inbit != 0) { ans.push_back(inbit + \u0026#39;0\u0026#39;); } string ansr(ans.rbegin(),ans.rend()); return ansr; } }; ","date":"2015-05-22T11:56:02Z","permalink":"https://blog.coinidea.com/en/p/leetcode_67add-binary/","title":"[leetcode_67]Add Binary"},{"content":"Given an array, find the next permutation of the sequence. If the sequence is already the largest permutation, output the smallest sorted order.\nThe key is to have a clear approach.\nFind the first element worth swapping \u0026ndash; it should be as close to the least significant position as possible, and there must be a larger element after it. Then find the smallest element after it that is larger and swap them.\nFinally, sort all elements after the swapped position in ascending order.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 int cmp(int a,int b) { return a \u0026lt; b; } class Solution { public: void nextPermutation(vector\u0026lt;int\u0026gt; \u0026amp;num) { bool IsSwap = false; for(int i = num.size()-1;i \u0026gt;= 0;i--) { int index = -1; int max = 0xffff; for(int j = i+1;j \u0026lt; num.size();j++) { if(num[j] \u0026gt; num[i] \u0026amp;\u0026amp; num[j] \u0026lt; max) { index = j; max = num[j]; IsSwap = true; } } if(IsSwap) { int tmp = num[index]; num[index] = num[i]; num[i] = tmp; sort(num.begin()+i+1,num.end(),cmp); break; } } if(IsSwap == false) { sort(num.begin(),num.end(),cmp); } } }; ","date":"2015-05-22T11:54:52Z","permalink":"https://blog.coinidea.com/en/p/leetcode_31next-permutation/","title":"[leetcode_31]Next Permutation"},{"content":"Insertion sort on a singly linked list. A simple problem in theory, but my implementation turned out messy. Maybe I should take a break from LeetCode for now. Starting the thesis topic tomorrow.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Solution { public: int GetCount(ListNode *head) { int count = 0; while(head != NULL) { count++; head=head-\u0026gt;next; } return count; } ListNode *insertionSortList(ListNode *head) { if(head == NULL)return head; ListNode * now = head-\u0026gt;next; ListNode * before = head; int count = GetCount(head); while(now != NULL) { ListNode * tmpnow = now-\u0026gt;next; if(now-\u0026gt;val \u0026lt;= head-\u0026gt;val) { ListNode * tmp = now-\u0026gt;next; before-\u0026gt;next = now-\u0026gt;next; now-\u0026gt;next = head; head = now; now = tmpnow; } else { ListNode * beforetmp = head; ListNode * tmp = beforetmp-\u0026gt;next; while(tmp != now \u0026amp;\u0026amp; tmp-\u0026gt;val \u0026lt;= now-\u0026gt;val) { beforetmp = beforetmp-\u0026gt;next; tmp = tmp-\u0026gt;next; } if(tmp != now) { beforetmp-\u0026gt;next = now; before-\u0026gt;next = now-\u0026gt;next; now-\u0026gt;next = tmp; now = tmpnow; } else { before = now; now = tmpnow; } } } ListNode * chead = head; for(int i = 1;i \u0026lt; count;i++) { chead = chead-\u0026gt;next; } chead-\u0026gt;next = NULL; return head; } }; ","date":"2015-05-22T11:52:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode_147insertion-sort-list/","title":"[leetcode_147]Insertion Sort List"},{"content":"Determine whether a binary tree is a valid BST.\nBased on BST properties, recursively validate.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public: bool result; enum Flag {left, right, leftright}; void isValidBSTStep(TreeNode * root, int val1, int val2, Flag flag) { switch(flag){ case left: if(root-\u0026gt;val \u0026lt;= val1) { result = false; return; } break; case right: if(root-\u0026gt;val \u0026gt;= val2) { result = false; return; } break; case leftright: if(root-\u0026gt;val \u0026lt;= val1 || root-\u0026gt;val \u0026gt;= val2) { result = false; return; } break; } if(root-\u0026gt;left != NULL) { if(flag == left || flag == leftright) isValidBSTStep(root-\u0026gt;left, val1, root-\u0026gt;val, leftright); else isValidBSTStep(root-\u0026gt;left, 0, root-\u0026gt;val, right); } if(root-\u0026gt;right != NULL ){ if(flag == right || flag == leftright) isValidBSTStep(root-\u0026gt;right, root-\u0026gt;val, val2, leftright); else isValidBSTStep(root-\u0026gt;right, root-\u0026gt;val, 0, left); } } bool isValidBST(TreeNode *root) { result = true; if(root == NULL) return result; if(root-\u0026gt;left != NULL) { isValidBSTStep(root-\u0026gt;left, 0, root-\u0026gt;val, right); } if(root-\u0026gt;right != NULL ){ isValidBSTStep(root-\u0026gt;right, root-\u0026gt;val, 0, left); } return result; } }; ","date":"2015-05-22T11:51:21Z","permalink":"https://blog.coinidea.com/en/p/leetcode_98-validate-binary-search-tree/","title":"[leetcode_98] Validate Binary Search Tree"},{"content":"Unbounded knapsack problem?\nGiven input 2 3 6 7,\noutput all combinations of 2, 3, 6, 7 that sum to 7.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 int cmp(int a,int b) { return a \u0026lt; b; } struct ValNode { ValNode():IsExist(false){set_v.clear();} vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;set_v; bool IsExist; }; class Solution { public: bool CheckIsExist(vector\u0026lt;int\u0026gt;\u0026amp;item_tmp,vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp;set_v) { sort(item_tmp.begin(),item_tmp.end(),cmp); for(int i = 0;i \u0026lt; set_v.size();i++) { if(item_tmp == set_v[i])return true; } return false; } vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; combinationSum(vector\u0026lt;int\u0026gt; \u0026amp;candidates, int target) { int max = target; ValNode *valnodes = new ValNode[max+1]; valnodes[0].IsExist = true; vector\u0026lt;int\u0026gt;item; item.clear(); valnodes[0].set_v.push_back(item); for(int i = 0;i \u0026lt;= target;i++) { if(valnodes[i].IsExist) { for(int j = 0;j \u0026lt; candidates.size();j++) { if(i + candidates[j] \u0026lt;= target) { valnodes[i+candidates[j]].IsExist = true; for(int k = 0;k \u0026lt; valnodes[i].set_v.size();k++) { vector\u0026lt;int\u0026gt;item_tmp; item_tmp.clear(); item_tmp = valnodes[i].set_v[k]; item_tmp.push_back(candidates[j]); if(!CheckIsExist(item_tmp,valnodes[i+candidates[j]].set_v)) valnodes[i+candidates[j]].set_v.push_back(item_tmp); } } } } } return valnodes[max].set_v; } }; ","date":"2015-05-22T11:49:33Z","permalink":"https://blog.coinidea.com/en/p/leetcode_39combination-sum/","title":"[leetcode_39]Combination Sum"},{"content":"Given n, generate all structurally unique BSTs that store values 1 to n.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Solution { public: vector\u0026lt;TreeNode *\u0026gt; genTreeNodes(int left,int right) { vector\u0026lt;TreeNode *\u0026gt; nodes; nodes.clear(); if(left \u0026gt; right) { nodes.push_back(NULL); return nodes; } if(left == right) { TreeNode * node = new TreeNode(left); nodes.push_back(node); return nodes; } for(int i = left;i\u0026lt;= right;i++) { vector\u0026lt;TreeNode *\u0026gt;lefts,rights; lefts.clear(); rights.clear(); lefts = genTreeNodes(left,i-1); rights = genTreeNodes(i+1,right); // Enumerate all combinations of left and right subtrees for(int l = 0;l \u0026lt; lefts.size();l++) { for(int r = 0; r \u0026lt; rights.size();r++) { TreeNode *node = new TreeNode(i); node-\u0026gt;left = lefts[l]; node-\u0026gt;right = rights[r]; nodes.push_back(node); } } } return nodes; } vector\u0026lt;TreeNode *\u0026gt; generateTrees(int n) { vector\u0026lt;TreeNode *\u0026gt;nodes; nodes.clear(); nodes = genTreeNodes(1,n); return nodes; } }; ","date":"2015-05-22T11:47:39Z","permalink":"https://blog.coinidea.com/en/p/leetcode_95unique-binary-search-trees-ii/","title":"[leetcode_95]Unique Binary Search Trees II"},{"content":"Implement pow. Watch out for timeout and negative n.\nUse binary exponentiation to achieve O(log n) complexity.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public: double powstep(double x,int n) { if(n == 0)return 1.0; if(n == 1)return x; if(n == 2)return x*x; if(n % 2 == 0) { return powstep(powstep(x,n/2),2); } else { return x * powstep(powstep(x,n/2),2); } } double pow(double x, int n) { int flag = 1; if(n \u0026lt; 0) flag = -1; n = (-1)*n; double ans = powstep(x,n); if(flag == -1) ans = 1.0 / ans; return ans; } }; ","date":"2015-05-22T11:46:03Z","permalink":"https://blog.coinidea.com/en/p/leetcode_50powx-n/","title":"[leetcode_50]Pow(x, n)"},{"content":"Partition a singly linked list. Choose a value x, then place all nodes with values less than x before those with values greater than or equal to x, while preserving the original relative order within each group.\nApproach:\nFirst, find the first node with a value less than x and move it to the front.\nThen, find the first node with a value greater than or equal to x.\nFrom there, enumerate the remaining nodes: if a node\u0026rsquo;s value is greater than or equal to x, skip it; if it is less than x, move it before the first node with a value greater than or equal to x.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class Solution { public: ListNode *partition(ListNode *head, int x) { if(head == NULL || head-\u0026gt;next == NULL) return head; ListNode * beforenode; ListNode * minnode, *maxnode; // find the 1st minnode if(head-\u0026gt;val \u0026lt; x) { minnode = head; } else { beforenode = head; minnode = head-\u0026gt;next; while(minnode != NULL \u0026amp;\u0026amp; minnode-\u0026gt;val \u0026gt;= x) { beforenode = minnode; minnode = minnode-\u0026gt;next; } if(minnode == NULL) return head; beforenode-\u0026gt;next = minnode-\u0026gt;next; minnode-\u0026gt;next = head; // now the head is minnode; } beforenode = minnode; maxnode = minnode-\u0026gt;next; while(maxnode != NULL \u0026amp;\u0026amp; maxnode-\u0026gt;val \u0026lt; x) { beforenode = maxnode; maxnode = maxnode-\u0026gt;next; } if(maxnode == NULL || maxnode-\u0026gt;next == NULL) return minnode; // now find minnode and maxnode. the head is minnode head = minnode; ListNode * now = maxnode-\u0026gt;next; while(now != NULL) { if(now-\u0026gt;val \u0026gt;= x) { maxnode = now; now = now-\u0026gt;next; } else { ListNode * tmp = beforenode-\u0026gt;next; maxnode-\u0026gt;next = now-\u0026gt;next; beforenode-\u0026gt;next = now; now-\u0026gt;next = tmp; now = maxnode-\u0026gt;next; beforenode = beforenode-\u0026gt;next; } } return head; } }; ","date":"2015-05-22T11:44:30Z","permalink":"https://blog.coinidea.com/en/p/leetcode_86partition-list/","title":"[leetcode_86]Partition List"},{"content":"Serialize a binary tree, but alternate the output direction between left-to-right and right-to-left for each level.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Solution { public: enum Direciton {left,right}; vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; zigzagLevelOrder(TreeNode *root) { vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; result; result.clear(); vector\u0026lt;TreeNode*\u0026gt; seq,seq_c; seq.clear(); if(root != NULL)seq.push_back(root); Direciton direction = left; while(seq.size() \u0026gt; 0) { seq_c.clear(); vector\u0026lt;int\u0026gt;item; item.clear(); if(direction == left) { direction = right; for(int i = 0; i \u0026lt; seq.size();i++) { item.push_back(seq[i]-\u0026gt;val); if(seq[i]-\u0026gt;left != NULL) { seq_c.push_back(seq[i]-\u0026gt;left); } if(seq[i]-\u0026gt;right != NULL) { seq_c.push_back(seq[i]-\u0026gt;right); } } } else { direction = left; for(int i = seq.size()-1; i \u0026gt;= 0; i--) { item.push_back(seq[i]-\u0026gt;val); } for(int i = 0; i \u0026lt; seq.size();i++) { if(seq[i]-\u0026gt;left != NULL) { seq_c.push_back(seq[i]-\u0026gt;left); } if(seq[i]-\u0026gt;right != NULL) { seq_c.push_back(seq[i]-\u0026gt;right); } } } result.push_back(item); seq = seq_c; } return result; } }; ","date":"2015-05-22T11:43:17Z","permalink":"https://blog.coinidea.com/en/p/leetcode_103binary-tree-zigzag-level-order-traversal/","title":"[leetcode_103]Binary Tree Zigzag Level Order Traversal"},{"content":"Flatten a binary tree.\nFlattening means transforming:\n1 2 3 4 5 1 / \\ 2 5 / \\ \\ 3 4 6 into:\n1 2 3 4 5 6 7 8 9 10 11 1 \\ 2 \\ 3 \\ 4 \\ 5 \\ 6 Each node’s right child points to the next node of a pre-order traversal.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public: TreeNode * flattenStep(TreeNode *root) { if(root-\u0026amp;gt;left == NULL \u0026amp;amp;\u0026amp;amp; root-\u0026amp;gt;right == NULL) return root; TreeNode * tmp = NULL; if(root-\u0026amp;gt;right != NULL) tmp = flattenStep(root-\u0026amp;gt;right); if(root-\u0026amp;gt;left != NULL) root-\u0026amp;gt;right = flattenStep(root-\u0026amp;gt;left); else root-\u0026amp;gt;right = NULL; root-\u0026amp;gt;left = NULL; if(tmp != NULL) { TreeNode * tmpright = root; while(tmpright-\u0026amp;gt;right != NULL) tmpright = tmpright-\u0026amp;gt;right; tmpright-\u0026amp;gt;right = tmp; } return root; } void flatten(TreeNode *root) { if(root == NULL)return; root = flattenStep(root); } }; ","date":"2015-05-22T11:42:05Z","permalink":"https://blog.coinidea.com/en/p/leetcode_114flatten-binary-tree-to-linked-list/","title":"[leetcode_114]Flatten Binary Tree to Linked List"},{"content":"The N-Queens problem \u0026ndash; output all solutions.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 class Solution { public: int count; int *x; int *y; int index; bool *rows, *cols, *ltrb, *rtlb; vector\u0026lt;vector\u0026lt;string\u0026gt;\u0026gt; ans; vector\u0026lt;string\u0026gt; item; void SetFalse(bool *arrayin, int n) { for(int i = 0; i \u0026lt; n; i++) arrayin[i] = false; } void Move(int row, int n) { for(int col = 0; col \u0026lt; n; col++) { if( rows[row] != true \u0026amp;\u0026amp; cols[col] != true \u0026amp;\u0026amp; ltrb[row+col] != true \u0026amp;\u0026amp; rtlb[n-1+row-col] != true) { if(row == n-1) { x[index] = row; y[index++] = col; item.clear(); string subitem = \u0026#34;\u0026#34;; for(int j = 0; j \u0026lt; n; j++) { subitem.push_back(\u0026#39;.\u0026#39;); } for(int i = 0; i \u0026lt; n; i++) { item.push_back(subitem); } for(int i = 0; i \u0026lt; index; i++) { item[x[i]][y[i]] = \u0026#39;Q\u0026#39;; } ans.push_back(item); index--; } else { rows[row] = true; cols[col] = true; ltrb[row+col] = true; rtlb[n-1+row-col] = true; x[index] = row; y[index++] = col; Move(row+1, n); index--; rows[row] = false; cols[col] = false; ltrb[row+col] = false; rtlb[n-1+row-col] = false; } } } } vector\u0026lt;vector\u0026lt;string\u0026gt;\u0026gt; solveNQueens(int n) { x = new int[n]; y = new int[n]; rows = new bool[n]; SetFalse(rows, n); cols = new bool[n]; SetFalse(cols, n); ltrb = new bool[n+n-1]; SetFalse(ltrb, n+n-1); rtlb = new bool[n+n-1]; SetFalse(rtlb, n+n-1); ans.clear(); if(n == 1) { string subitem = \u0026#34;Q\u0026#34;; vector\u0026lt;string\u0026gt; item; item.clear(); item.push_back(subitem); ans.push_back(item); return ans; } int row = 0; index = 0; for(int col = 0; col \u0026lt; n; col++) { rows[row] = true; cols[col] = true; ltrb[row+col] = true; rtlb[n-1+row-col] = true; x[index] = row; y[index++] = col; Move(row+1, n); index--; rows[row] = false; cols[col] = false; ltrb[row+col] = false; rtlb[n-1+row-col] = false; } return ans; } }; ","date":"2015-05-22T11:40:54Z","permalink":"https://blog.coinidea.com/en/p/leetcode_51n-queens/","title":"[leetcode_51]N-Queens"},{"content":"The N-Queens problem \u0026ndash; just output the number of solutions.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Solution { public: int count; bool *rows,*cols,*ltrb,*rtlb; void SetFalse(bool *arrayin,int n) { for(int i = 0;i \u0026lt; n;i++) arrayin[i] = false; } void Move(int row,int n) { for(int col = 0;col \u0026lt; n;col++) { if( rows[row] != true \u0026amp;\u0026amp; cols[col] != true \u0026amp;\u0026amp; ltrb[row+col] != true\u0026amp;\u0026amp; rtlb[n-1+row-col] != true) { if(row == n-1)count++; else { rows[row] = true; cols[col] = true; ltrb[row+col] = true; rtlb[n-1+row-col] = true; Move(row+1,n); rows[row] = false; cols[col] = false; ltrb[row+col] = false; rtlb[n-1+row-col] = false; } } } } int totalNQueens(int n) { rows = new bool[n];//行 SetFalse(rows,n); cols = new bool[n];//列 SetFalse(cols,n); ltrb = new bool[n+n-1]; SetFalse(ltrb,n+n-1); rtlb = new bool[n+n-1]; SetFalse(rtlb,n+n-1); count = 0; if(n == 1)return 1; int row = 0; for(int col = 0;col \u0026lt; n;col++) { rows[row] = true; cols[col] = true; ltrb[row+col] = true; rtlb[n-1+row-col] = true; Move(row+1,n); rows[row] = false; cols[col] = false; ltrb[row+col] = false; rtlb[n-1+row-col] = false; } return count; } }; ","date":"2015-05-22T11:39:37Z","permalink":"https://blog.coinidea.com/en/p/leetcode_52n-queens-ii/","title":"[leetcode_52]N-Queens II"},{"content":"Find the longest consecutive subsequence in an unsorted array.\nTo be honest, I could not solve this problem in O(n) complexity on my own.\nI understood the approach only after reading someone else\u0026rsquo;s code.\nI had thought about using a hash, but I recalled that STL\u0026rsquo;s map has O(log n) lookup complexity, which would result in an overall O(n log n) complexity, so I gave up on that idea.\nToday I took the time to properly understand what hash tables are, and the differences between map, set, hash_map, and hash_set. It was quite helpful.\nI also learned about a library called Boost, which is a quasi-standard C++ library. Feel free to look it up if you are interested.\nThe final solution for this problem is hash + left-right expansion simulation.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public: ListNode * GetListNthNode(ListNode * head, int n) { int k = 0; while(k \u0026lt; n) { k++; head = head-\u0026gt;next; } return head; } int CountList(ListNode *head) { int count = -1; while(head != NULL) { head = head-\u0026gt;next; count++; } return count; } TreeNode *BSearchT(int left, int right, ListNode * head) { if(right \u0026lt; left) return NULL; int mid = (left + right) / 2; TreeNode * root = new TreeNode(GetListNthNode(head, mid - left)-\u0026gt;val); root-\u0026gt;left = BSearchT(left, mid - 1, head); root-\u0026gt;right = BSearchT(mid + 1, right, GetListNthNode(head, mid + 1 - left)); return root; } TreeNode *sortedListToBST(ListNode *head) { if(head == NULL) return NULL; int n = CountList(head); int mid = (0 + n) / 2; TreeNode * root = new TreeNode(GetListNthNode(head, mid)-\u0026gt;val); root-\u0026gt;left = BSearchT(0, mid - 1, head); root-\u0026gt;right = BSearchT(mid + 1, n, GetListNthNode(head, mid + 1)); return root; } }; ","date":"2015-05-22T11:29:11Z","permalink":"https://blog.coinidea.com/en/p/leetcode_128-longest-consecutive-sequence/","title":"[leetcode_128] Longest Consecutive Sequence"},{"content":"This problem is a variation of http://blog.sina.com.cn/s/blog_672f71fc0101os5r.html.\nThe only difference is that the array is replaced with a singly linked list. When searching in the linked list, be careful to optimize: after each binary split, the head node remains the same for the left part, but for the right part, the head node needs to be updated to the mid node. Otherwise it will time out.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public: ListNode * GetListNthNode(ListNode * head, int n) { int k = 0; while(k \u0026lt; n) { k++; head = head-\u0026gt;next; } return head; } int CountList(ListNode *head) { int count = -1; while(head != NULL) { head = head-\u0026gt;next; count++; } return count; } TreeNode *BSearchT(int left, int right, ListNode * head) { if(right \u0026lt; left) return NULL; int mid = (left + right) / 2; TreeNode * root = new TreeNode(GetListNthNode(head, mid - left)-\u0026gt;val); root-\u0026gt;left = BSearchT(left, mid - 1, head); root-\u0026gt;right = BSearchT(mid + 1, right, GetListNthNode(head, mid + 1 - left)); return root; } TreeNode *sortedListToBST(ListNode *head) { if(head == NULL) return NULL; int n = CountList(head); int mid = (0 + n) / 2; TreeNode * root = new TreeNode(GetListNthNode(head, mid)-\u0026gt;val); root-\u0026gt;left = BSearchT(0, mid - 1, head); root-\u0026gt;right = BSearchT(mid + 1, n, GetListNthNode(head, mid + 1)); return root; } }; ","date":"2015-05-22T11:27:51Z","permalink":"https://blog.coinidea.com/en/p/leetcode_109convert-sorted-list-to-binary-search-tree/","title":"[leetcode_109]Convert Sorted List to Binary Search Tree"},{"content":"A simulation problem. Just iterate until n.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public: string SayStep(string str) { string strstep = \u0026#34;\u0026#34;; int index = 0; while(index \u0026lt; str.length()) { char c = str[index]; int count_c = 1; int i; for(i = index+1;i \u0026lt; str.length();i++) { if(c == str[i])count_c++; else break; } index = i; strstep.push_back(count_c + \u0026#39;0\u0026#39;); strstep.push_back(c); } return strstep; } string countAndSay(int n) { string str = \u0026#34;1\u0026#34;; for(int i = 1; i \u0026lt; n;i++) { str = SayStep(str); } return str; } }; ","date":"2015-05-22T11:26:08Z","permalink":"https://blog.coinidea.com/en/p/leetcode_38count-and-say/","title":"[leetcode_38]Count and Say"},{"content":"Marking from front to back one by one will time out. After some thought, in certain cases the complexity is O(n^2).\nHowever, marking from back to front is different \u0026ndash; it is approximately O(n).\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public: void FindMin(int A[],int n,bool flag[]) { if(n \u0026lt;= 0)return; int min = 0xffff; for(int i = n-1;i \u0026gt;= 0;i--) { if(A[i] + i \u0026gt;= n) { flag[i] = true; if(min \u0026gt; i) min = i; } } if(min == 0xffff || flag[0] == true)return; FindMin(A,min,flag); } bool canJump(int A[], int n) { bool * flag = new bool[n+1]; if(n == 1)return true; for(int i = 0;i \u0026lt; n;i++) { flag[i] = false; } FindMin(A,n-1,flag); return flag[0]; } }; ","date":"2015-05-22T11:24:56Z","permalink":"https://blog.coinidea.com/en/p/leetcode_55jump-game/","title":"[leetcode_55]Jump Game"},{"content":"A variation of binary search. Given a sorted array with duplicate numbers allowed, find the range of the target. If the target does not exist, output [-1,-1].\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public: void bSearch(int A[],int left,int right,int target,int flag,int \u0026amp;val) { if(left \u0026gt; right) return; int mid = (left + right) / 2; if(A[mid] == target) { val = mid; if(flag == 0) { bSearch(A, left, mid-1, target, flag, val); } else { bSearch(A, mid+1, right, target, flag, val); } } else { if(A[mid] \u0026lt; target) { bSearch(A, mid+1, right, target, flag, val); } else { bSearch(A, left, mid-1, target, flag, val); } } } vector\u0026lt;int\u0026gt; searchRange(int A[], int n, int target) { vector\u0026lt;int\u0026gt; ans; ans.clear(); int left = -1; int right = -1; bSearch(A, 0, n-1, target, 0, left); bSearch(A, 0, n-1, target, 1, right); ans.push_back(left); ans.push_back(right); return ans; } }; ","date":"2015-05-22T11:23:45Z","permalink":"https://blog.coinidea.com/en/p/leetcode_34search-for-a-range/","title":"[leetcode_34]Search for a Range"},{"content":"A variation of http://blog.sina.com.cn/s/blog_672f71fc0101phtr.html.\nDuplicate numbers are allowed, but duplicate subsets must be removed from the result.\nInitially got TLE. After a small optimization: when checking whether the current subset already exists, iterate from back to front and stop as soon as the size differs.\nIf it still timed out, the plan was to use a map.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 int cmp(int a,int b) { return a \u0026lt; b; } class Solution { public: bool CheckIn(vector\u0026lt;int\u0026gt; item1,vector\u0026lt;int\u0026gt; item2) { if(item1.size() != item2.size())return false; for(int i = 0;i \u0026lt; item1.size();i++) { if(item1[i] != item2[i])return false; } return true; } void AddItemStep(int i,int k,vector\u0026lt;int\u0026gt;\u0026amp;S,vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp;ans,vector\u0026lt;int\u0026gt;\u0026amp;item) { if(item.size() == k) { for(int i = ans.size()-1;i \u0026gt;= 0\u0026amp;\u0026amp;item.size() == ans[i].size();i--) { if(CheckIn(item,ans[i]) == true)return; } ans.push_back(item); return; } else { if(i \u0026gt;= S.size())return; item.push_back(S[i]); AddItemStep(i+1,k,S,ans,item); item.pop_back(); AddItemStep(i+1,k,S,ans,item); } } void AddItem(int k,vector\u0026lt;int\u0026gt; \u0026amp;S,vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp;ans) { int i = 0; vector\u0026lt;int\u0026gt; item; item.clear(); AddItemStep(i,k,S,ans,item); } vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; subsetsWithDup(vector\u0026lt;int\u0026gt; \u0026amp;S) { sort(S.begin(),S.end(),cmp); vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;ans; ans.clear(); vector\u0026lt;int\u0026gt;item; item.clear(); ans.push_back(item); for(int i = 1;i \u0026lt;= S.size();i++) { AddItem(i,S,ans); } return ans; } }; ","date":"2015-05-22T02:05:45Z","permalink":"https://blog.coinidea.com/en/p/leetcode_90subsets-ii/","title":"[leetcode_90]Subsets II"},{"content":"A variation of Unique Paths\nhttp://blog.sina.com.cn/s/blog_672f71fc0101pf1c.html. With obstacles added, just add a check for them.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 struct PPoint { int x; int y; }; class Solution { public: bool CheckIn(int x,int y,PPoint *p,int top) { for(int i = 0;i \u0026lt; top;i++) { if(x == p[i].x \u0026amp;\u0026amp; y == p[i].y) { return true; } } return false; } int uniquePathsWithObstacles(vector\u0026lt;vector\u0026lt;int\u0026gt; \u0026gt; \u0026amp;obstacleGrid) { int m = obstacleGrid.size(); if(m \u0026lt;= 0 )return 0; int n = obstacleGrid[0].size(); if(obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1)return 0; for(int i = 0;i \u0026lt; m;i++) for(int j = 0;j \u0026lt; n;j++) if(obstacleGrid[i][j] == 1)obstacleGrid[i][j] = -1; PPoint *p = new PPoint[m+n]; PPoint *p_c = new PPoint[m+n]; int index = 0; p[index].x = 0; p[index++].y = 0; obstacleGrid[0][0] = 1; while(true) { int top = 0; for(int i = 0;i \u0026lt; index;i++) { int x = p[i].x; int y = p[i].y; if(x + 1 \u0026lt; m \u0026amp;\u0026amp; obstacleGrid[x+1][y] != -1) { obstacleGrid[x+1][y] += obstacleGrid[x][y]; if(CheckIn(x+1,y,p_c,top) == false) { p_c[top].x = x+1; p_c[top++].y = y; } } if(y + 1 \u0026lt; n \u0026amp;\u0026amp; obstacleGrid[x][y+1] != -1) { obstacleGrid[x][y+1] += obstacleGrid[x][y]; if(CheckIn(x,y+1,p_c,top) == false) { p_c[top].x = x; p_c[top++].y = y+1; } } } if(top == 0) break; index = top; for(int i = 0;i \u0026lt; top;i++) { p[i].x = p_c[i].x; p[i].y = p_c[i].y; } } return obstacleGrid[m-1][n-1]; } }; ","date":"2015-05-22T02:04:32Z","permalink":"https://blog.coinidea.com/en/p/leetcode_63unique-paths-ii/","title":"[leetcode_63]Unique Paths II"},{"content":"Given a set of strings, find their longest common prefix.\nJust compare them one by one.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public: bool EqualAll(vector\u0026lt;string\u0026gt;\u0026amp; strs, int k) { for(int i = 1; i \u0026lt; strs.size(); i++) { if(strs[i][k] != strs[0][k]) return false; } return true; } string longestCommonPrefix(vector\u0026lt;string\u0026gt;\u0026amp; strs) { string ans = \u0026#34;\u0026#34;; if(strs.size() \u0026lt;= 0) return ans; int len = 0xffff; for(int i = 0; i \u0026lt; strs.size(); i++) { if(strs[i].size() \u0026lt; len) len = strs[i].size(); } for(int i = 0; i \u0026lt; len; i++) { if(EqualAll(strs, i)) ans.push_back(strs[0][i]); else return ans; } return ans; } }; ","date":"2015-05-22T01:58:14Z","permalink":"https://blog.coinidea.com/en/p/leetcode_14longest-common-prefix/","title":"[leetcode_14]Longest Common Prefix"},{"content":"Given a binary tree root and a target value, find all paths from the root to leaf nodes where the path sum equals the target.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public: void MoveOnPath(TreeNode *node,int sum,int \u0026amp;val,vector\u0026lt;int\u0026gt;\u0026amp;item,vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp;ans) { if(node == NULL) return; if(node-\u0026gt;left == NULL \u0026amp;\u0026amp; node-\u0026gt;right == NULL) { if(sum == val) ans.push_back(item); return; } if(node-\u0026gt;left != NULL) { val += node-\u0026gt;left-\u0026gt;val; item.push_back(node-\u0026gt;left-\u0026gt;val); MoveOnPath(node-\u0026gt;left, sum, val, item, ans); val -= node-\u0026gt;left-\u0026gt;val; item.pop_back(); } if(node-\u0026gt;right != NULL) { val += node-\u0026gt;right-\u0026gt;val; item.push_back(node-\u0026gt;right-\u0026gt;val); MoveOnPath(node-\u0026gt;right, sum, val, item, ans); val -= node-\u0026gt;right-\u0026gt;val; item.pop_back(); } } vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; pathSum(TreeNode *root, int sum) { vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; ans.clear(); if(root == NULL) return ans; int val = 0; vector\u0026lt;int\u0026gt; item; item.clear(); val += root-\u0026gt;val; item.push_back(root-\u0026gt;val); MoveOnPath(root, sum, val, item, ans); return ans; } }; ","date":"2015-05-22T01:56:30Z","permalink":"https://blog.coinidea.com/en/p/leetcode_113path-sum-ii/","title":"[leetcode_113]Path Sum II"},{"content":"Given an array, e.g., {1,2,3,4}, find all subsets of the set.\nGot one WA because the result needs to be in ascending order.\nA search approach works.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 int cmp(int a,int b) { return a \u0026lt; b; } class Solution { public: void AddItemStep(int i,int k,vector\u0026lt;int\u0026gt;\u0026amp;S,vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp;ans,vector\u0026lt;int\u0026gt;\u0026amp;item) { if(item.size() == k) { ans.push_back(item); return; } else { if(i \u0026gt;= S.size())return; item.push_back(S[i]); AddItemStep(i+1,k,S,ans,item); item.pop_back(); AddItemStep(i+1,k,S,ans,item); } } void AddItem(int k,vector\u0026lt;int\u0026gt; \u0026amp;S,vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp;ans) { int i = 0; vector\u0026lt;int\u0026gt; item; item.clear(); AddItemStep(i,k,S,ans,item); } vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; subsets(vector\u0026lt;int\u0026gt; \u0026amp;S) { sort(S.begin(),S.end(),cmp); vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;ans; ans.clear(); vector\u0026lt;int\u0026gt;item; item.clear(); ans.push_back(item); for(int i = 1;i \u0026lt;= S.size();i++) { AddItem(i,S,ans); } return ans; } }; ","date":"2015-05-22T01:55:18Z","permalink":"https://blog.coinidea.com/en/p/leetcode_78subsets/","title":"[leetcode_78]Subsets"},{"content":"Given a string s consisting of spaces and letters, find the length of the last word. A word is defined as consisting only of letters.\nclass Solution { public: int lengthOfLastWord(const char *s) { int length = strlen(s); int index = length - 1; while(s[index] == ' ')index--; int ans = 0; for(int i = index;i \u0026gt;= 0\u0026\u0026s[i] != ' ';i--) ans++; return ans; } }; ","date":"2015-05-22T01:54:03Z","permalink":"https://blog.coinidea.com/en/p/leetcode_58length-of-last-word/","title":"[leetcode_58]Length of Last Word"},{"content":"Given an array and a target, find three numbers in the array whose sum is closest to the target. A unique solution is guaranteed.\nA brute-force approach will time out.\nYou can sort the array, use two nested loops for brute force, and then apply binary search for the third layer. This avoids the timeout.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 int cmp(int a,int b) { return a \u0026lt; b; } class Solution { public: int bSearch(int tmp,int left,vector\u0026lt;int\u0026gt;\u0026amp;num,int right) { if(right - left \u0026lt;= 1) { if(abs(tmp - num[left]) \u0026lt; abs(tmp - num[right])) { return num[left]; } else { return num[right]; } } int mid = (left + right) / 2; if(num[mid] == tmp)return tmp; else if(num[mid] \u0026gt; tmp) { return bSearch(tmp,left,num,mid-1); } else { return bSearch(tmp,mid+1,num,right); } } int threeSumClosest(vector\u0026lt;int\u0026gt; \u0026amp;num, int target) { // Note: The Solution object is instantiated only once and is reused by each test case. int sum = 0; int dis = 0xffff; sort(num.begin(),num.end(),cmp); for(int i = 0;i \u0026lt; num.size()-2;i++) { for(int j = i+1;j \u0026lt; num.size()-1;j++) { int tmp = num[i] + num[j]; tmp += bSearch(target-tmp,j+1,num,num.size()-1); if(abs(tmp-target) \u0026lt; dis) { sum = tmp; dis = abs(tmp-target); } } } return sum; } }; ","date":"2015-05-22T01:52:59Z","permalink":"https://blog.coinidea.com/en/p/leetcode_163sum-closest/","title":"[leetcode_16]3Sum Closest"},{"content":"As required by the problem, calculate the amount of trapped water.\nFirst, find the maximum value within a segment that is greater than the smaller of the two boundary values. If such a value exists, split the problem into left + max index and max index + right.\nIf no such maximum exists, it means both boundaries are larger than all middle elements, so simply sum up the trapped water.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public: int sum; void WaterStep(int A[],int left,int right) { int min = A[left] \u0026gt; A[right] ? A[right] : A[left]; int max = min; int index = -1; for(int i = left+1; i \u0026lt; right; i++) { if(A[i] \u0026gt; max) { index = i; max = A[i]; } } if(index == -1) { for(int i = left+1; i \u0026lt; right; i++) sum += min - A[i]; } else { WaterStep(A, left, index); WaterStep(A, index, right); } } int trap(int A[], int n) { sum = 0; WaterStep(A, 0, n-1); return sum; } }; ","date":"2015-05-22T01:51:54Z","permalink":"https://blog.coinidea.com/en/p/leetcode_42-trapping-rain-water/","title":"[leetcode_42] Trapping Rain Water"},{"content":"Given a string containing only the characters (){}[], determine whether they are properly matched.\nA stack can solve this problem.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public: bool IsMatch(char left,char right) { if(left == \u0026#39;{\u0026#39; \u0026amp;\u0026amp; right == \u0026#39;}\u0026#39; || left == \u0026#39;[\u0026#39; \u0026amp;\u0026amp; right == \u0026#39;]\u0026#39; || left == \u0026#39;(\u0026#39; \u0026amp;\u0026amp; right == \u0026#39;)\u0026#39;) { return true; } else return false; } bool isValid(string s) { stack\u0026lt;int\u0026gt; sta; for(int i = 0;i \u0026lt; s.length();i++) { if(sta.size() == 0 || IsMatch(sta.top(),s[i]) == false) { sta.push(s[i]); } else { sta.pop(); } } if(sta.size() == 0) { return true; } else return false; } }; ","date":"2015-05-22T01:50:51Z","permalink":"https://blog.coinidea.com/en/p/leetcode_20valid-parentheses/","title":"[leetcode_20]Valid Parentheses"},{"content":"A binary tree where each node from root to leaf stores a digit from 0 to 9. Calculate the sum of all numbers formed from root to leaf paths. Search from the root to each leaf node, convert the string to a number, and add it to the result.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public: int ConvertNumber(string \u0026amp;tmpNumber) { int number = 0; for(int i = 0;i \u0026lt; tmpNumber.length();i++) { number += (tmpNumber[tmpNumber.length() - 1 - i] - \u0026#39;0\u0026#39;)*pow(10.0,i); } return number; } void AddNextLevel(TreeNode *node,int \u0026amp;sum,string tmpNumber) { tmpNumber.push_back(node-\u0026gt;val + \u0026#39;0\u0026#39; - 0); if(node-\u0026gt;left == NULL \u0026amp;\u0026amp; node-\u0026gt;right == NULL) { sum += ConvertNumber(tmpNumber); return ; } if(node-\u0026gt;left != NULL) { AddNextLevel(node-\u0026gt;left,sum,tmpNumber); } if(node-\u0026gt;right != NULL) { AddNextLevel(node-\u0026gt;right,sum,tmpNumber); } } int sumNumbers(TreeNode *root) { int sum = 0; if(root == NULL)return sum; string tmpNumber = \u0026#34;\u0026#34;; AddNextLevel(root,sum,tmpNumber); return sum; } }; ","date":"2015-05-22T01:49:43Z","permalink":"https://blog.coinidea.com/en/p/leetcode_129-sum-root-to-leaf-numbers/","title":"[leetcode_129] Sum Root to Leaf Numbers"},{"content":"Find the minimum depth of a binary tree, calculated level by level. I used search with pruning. BFS might be faster in terms of time but requires extra space.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public: int min; void MoveTo(TreeNode *node, int steps) { if (node-\u0026gt;left == NULL \u0026amp;\u0026amp; node-\u0026gt;right == NULL) { if (steps \u0026lt; min) { min = steps; } return; } if (node-\u0026gt;left != NULL \u0026amp;\u0026amp; steps + 1 \u0026lt; min) { MoveTo(node-\u0026gt;left, steps + 1); } if (node-\u0026gt;right != NULL \u0026amp;\u0026amp; steps + 1 \u0026lt; min) { MoveTo(node-\u0026gt;right, steps + 1); } } int minDepth(TreeNode *root) { min = 999999999; if (root == NULL) return 0; MoveTo(root, 1); return min; } }; ","date":"2015-05-22T01:48:19Z","permalink":"https://blog.coinidea.com/en/p/leetcode_111-minimum-depth-of-binary-tree/","title":"[leetcode_111] Minimum Depth of Binary Tree"},{"content":"A variation of Populating Next Right Pointers in Each Node:\nhttp://blog.sina.com.cn/s/blog_672f71fc0101ohqp.html\nHowever, it seems like I didn\u0026rsquo;t use constant space.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution { public: void connect(TreeLinkNode *root) { // Note: The Solution object is instantiated only once and is reused by each test case. int height = -1; TreeLinkNode * rootheight = root; while(rootheight != NULL) { height++; rootheight = rootheight-\u0026gt;left; } int NumOfNodes = (int)pow(2.0,height+1) - 1; TreeLinkNode ** LinkNodeArray = new TreeLinkNode *[1000000]; int index = 0; LinkNodeArray[index++] = root; int bottom = 0; int top = index; while(true) { if(bottom == top) break; for(int i = bottom;i \u0026lt; top;i++) { if(LinkNodeArray[i] == NULL) continue; if(i == top-1) { LinkNodeArray[i] -\u0026gt;next = NULL; if(LinkNodeArray[i]-\u0026gt;left != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;left; if(LinkNodeArray[i]-\u0026gt;right != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;right; } else { LinkNodeArray[i] -\u0026gt;next = LinkNodeArray[i+1]; if(LinkNodeArray[i]-\u0026gt;left != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;left; if(LinkNodeArray[i]-\u0026gt;right != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;right; } } bottom = top; top = index; } } }; ","date":"2015-05-22T01:47:16Z","permalink":"https://blog.coinidea.com/en/p/leetcode_117-populating-next-right-pointers-in-each-node-ii/","title":"[leetcode_117] Populating Next Right Pointers in Each Node II"},{"content":"A variation of the previous Search in Rotated Sorted Array problem.\nOriginal post\nThis time, the array allows duplicates. I modified the code\u0026rsquo;s conditional logic accordingly.\nStill O(log n).\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution { public: bool searchStep(int A[],int target,int left,int right) { if(left \u0026gt; right) return false; int mid = (left+right)/2; if(A[mid] == target) return true; else if(A[mid] \u0026gt; target) { if(A[right] \u0026gt; A[left]) return searchStep(A,target,left,mid-1); else return searchStep(A,target,left,mid-1) || searchStep(A,target,mid+1,right); } else { if(A[right] \u0026gt; A[left]) return searchStep(A,target,mid+1,right); else return searchStep(A,target,mid+1,right) || searchStep(A,target,left,mid-1); } } bool search(int A[], int n, int target) { int left = 0; int right = n-1; return searchStep(A,target,left,right); } }; ","date":"2015-05-22T01:45:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode_81-search-in-rotated-sorted-array-ii/","title":"[leetcode_81] Search in Rotated Sorted Array II"},{"content":"Given a sorted array that has been rotated. For example: 0 1 2 3 4 5 6 7 8 9 after rotation becomes: 7 8 9 0 1 2 3 4 5 6\nGiven a target, return its index if it exists in the array, otherwise return -1.\nObviously, anyone can think of an O(n) approach.\nCan we do better? O(log n)? Binary search? Just modify binary search a bit:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public: int ans; void searchStep(int A[],int target,int left,int right) { if(left \u0026gt; right) return; int mid = (left+right)/2; if(A[mid] == target) { ans = mid; return; } else { if(A[mid] \u0026gt; target) { if(A[right] \u0026gt; A[left]) { searchStep(A,target,left,mid-1); } else { searchStep(A,target,left,mid-1); searchStep(A,target,mid+1,right); } } else { if(A[right] \u0026gt; A[left]) { searchStep(A,target,mid+1,right); } else { searchStep(A,target,mid+1,right); searchStep(A,target,left,mid-1); } } } } int search(int A[], int n, int target) { int left = 0; int right = n-1; ans = -1; searchStep(A,target,left,right); return ans; } }; ","date":"2015-05-22T01:44:32Z","permalink":"https://blog.coinidea.com/en/p/leetcode_33-search-in-rotated-sorted-array/","title":"[leetcode_33] Search in Rotated Sorted Array"},{"content":"A simple search problem, though the problem statement wasn\u0026rsquo;t very clear (or maybe my English isn\u0026rsquo;t great). Basically, given n, the universal set is 1, 2, 3\u0026hellip;n. Choose k elements to form subsets, and enumerate all such subsets.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public: void combineStep(int n, int step, int k, vector\u0026lt;int\u0026gt;\u0026amp; item, vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt;\u0026amp; ans, int count) { if(step \u0026gt; n+1) return; if(count == k) { ans.push_back(item); return ; } else { item.push_back(step); combineStep(n, step+1, k, item, ans, count+1); item.pop_back(); combineStep(n, step+1, k, item, ans, count); } } vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; combine(int n, int k) { vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; ans.clear(); vector\u0026lt;int\u0026gt; item; item.clear(); combineStep(n, 1, k, item, ans, 0); return ans; } }; ","date":"2015-05-22T01:43:16Z","permalink":"https://blog.coinidea.com/en/p/leetcode_77-combinations/","title":"[leetcode_77] Combinations"},{"content":"Determine whether a linked list has a cycle, and return the node where the cycle begins. If there is no cycle, return NULL.\nDetecting whether a linked list has a cycle without allocating extra space was mentioned in a previous blog post:\nhttp://blog.sina.com.cn/s/blog_672f71fc0101odsf.html\nHow to find the entry node of the cycle?\nIf we can calculate the number of nodes k in the cycle, then using the approach of removing the nth node from the end:\nhttp://blog.sina.com.cn/s/blog_672f71fc0101pfx6.html\nThis problem can be solved.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Solution { public: ListNode *detectCycle(ListNode *head) { if(head == NULL) return NULL; ListNode * p1 = head; ListNode * p2 = head-\u0026gt;next; if(p2 == NULL) return NULL; p2 = head-\u0026gt;next; while(true) { if(p2 == NULL) { return NULL; } else if(p1 == p2) { break; } else { p1 = p1-\u0026gt;next; p2 = p2-\u0026gt;next; if(p2 == NULL)return NULL; p2 = p2-\u0026gt;next; } } int k = 1; p1 = p1-\u0026gt;next; p2 = p2-\u0026gt;next-\u0026gt;next; while(p1 != p2) { p1 = p1-\u0026gt;next; p2 = p2-\u0026gt;next-\u0026gt;next; k++; } p1 = head; p2 = head; for(int i = 0;i \u0026lt; k;i++) { p2 = p2-\u0026gt;next; } while(p1 != p2) { p1 = p1-\u0026gt;next; p2 = p2-\u0026gt;next; } return p1; } }; ","date":"2015-05-22T01:42:11Z","permalink":"https://blog.coinidea.com/en/p/leetcode_142-linked-list-cycle-ii/","title":"[leetcode_142] Linked List Cycle II"},{"content":"Given a singly linked list, remove the nth node from the end. Try to do it in one pass.\nUse two pointers with a gap of exactly n between them. When the second pointer reaches NULL, remove the node at the first pointer.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public: ListNode *removeNthFromEnd(ListNode *head, int n) { ListNode *before = NULL; ListNode *p1 = head; ListNode *p2 = head; if(n \u0026lt;= 0) return head; for(int i = 0; i \u0026lt; n; i++) { p2 = p2-\u0026gt;next; } while(p2 != NULL) { p2 = p2-\u0026gt;next; before = p1; p1 = p1-\u0026gt;next; } if(before == NULL) { return head-\u0026gt;next; } else { before-\u0026gt;next = p1-\u0026gt;next; return head; } } }; ","date":"2015-05-22T01:40:35Z","permalink":"https://blog.coinidea.com/en/p/leetcode_19-remove-nth-node-from-end-of-list/","title":"[leetcode_19] Remove Nth Node From End of List"},{"content":"A simulation problem, but it was quite tedious to implement.\nAC on the first try:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public: int removeDuplicates(int A[], int n) { if(n == 0) return n; int now; int count = 0; int len = n; for(int i = 0; i \u0026lt; len; i++) { if(count == 0 || now != A[i]) { count = 1; now = A[i]; continue; } if(A[i] == now) { if(count == 2) { int dis = 0; int tmp = A[i]; for(int j = i+1; j \u0026lt; len; j++) { if(tmp == A[j]) { dis++; } else { A[j-1-dis] = A[j]; } } len -= 1 + dis; i--; } else { count++; } } } return len; } }; ","date":"2015-05-22T01:39:17Z","permalink":"https://blog.coinidea.com/en/p/leetcode_80-remove-duplicates-from-sorted-array-ii/","title":"[leetcode_80] Remove Duplicates from Sorted Array II"},{"content":"Given an mn matrix, set the entire row and column to 0 for every element that is 0.\nThe simplest approach is to use an mn matrix to record positions, then set accordingly.\nAn even simpler approach: use an m+n array to record which rows and columns need to be zeroed.\nAn even simpler constant-space approach — I thought of one, but it has some issues. Still working on it. For now, here\u0026rsquo;s the m+n solution.\nAC on the first try.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Solution { public: void setRZeros(vector\u0026lt;vector\u0026lt;int\u0026gt; \u0026gt; \u0026amp;matrix,int x) { int m = matrix.size(); int n = matrix[0].size(); for(int i = 0;i \u0026lt; n;i++) { matrix[x][i] = 0; } } void setCZeros(vector\u0026lt;vector\u0026lt;int\u0026gt; \u0026gt; \u0026amp;matrix,int y) { int m = matrix.size(); int n = matrix[0].size(); for(int i = 0;i \u0026lt; m;i++) { matrix[i][y] = 0; } } void setZeroes(vector\u0026lt;vector\u0026lt;int\u0026gt; \u0026gt; \u0026amp;matrix) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. int m = matrix.size(); int n = matrix[0].size(); int *R = new int[m]; int *C = new int[n]; memset(R,0,m*sizeof(int)); memset(C,0,n*sizeof(int)); for(int i = 0;i \u0026lt; m;i++) { for(int j = 0;j \u0026lt; n;j++) { if(matrix[i][j] == 0) { R[i] = 1; C[j] = 1; } } } for(int i = 0;i \u0026lt; m;i++) { if(R[i]) setRZeros(matrix,i); } for(int i = 0;i \u0026lt; n;i++) { if(C[i]) setCZeros(matrix,i); } } }; ","date":"2015-05-22T01:38:02Z","permalink":"https://blog.coinidea.com/en/p/leetcode_73-set-matrix-zeroes/","title":"[leetcode_73] Set Matrix Zeroes"},{"content":"The original image link for this problem is broken, but based on the description: given an m*n matrix, find how many paths exist from point (0, 0) to point (m-1, n-1).\nThe movement rule is that each step can only go right or down from the current position.\nBreadth-first search.\nHere is the code:\nAC on the first try. The code performance is probably not optimal.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 struct PPoint { int x; int y; }; class Solution { public: bool CheckIn(int x, int y, PPoint *p, int top) { for(int i = 0; i \u0026lt; top; i++) { if(x == p[i].x \u0026amp;\u0026amp; y == p[i].y) { return true; } } return false; } int uniquePaths(int m, int n) { int **map = new int*[m]; for(int i = 0; i \u0026lt; m; i++) { map[i] = new int[n]; } for(int i = 0; i \u0026lt; m; i++) { for(int j = 0; j \u0026lt; n; j++) { map[i][j] = 0; } } map[0][0] = 1; PPoint *p = new PPoint[m+n]; PPoint *p_c = new PPoint[m+n]; int index = 0; p[index].x = 0; p[index++].y = 0; while(true) { int top = 0; for(int i = 0; i \u0026lt; index; i++) { int x = p[i].x; int y = p[i].y; if(x + 1 \u0026lt; m) { map[x+1][y] += map[x][y]; if(CheckIn(x+1, y, p_c, top) == false) { p_c[top].x = x+1; p_c[top++].y = y; } } if(y + 1 \u0026lt; n) { map[x][y+1] += map[x][y]; if(CheckIn(x, y+1, p_c, top) == false) { p_c[top].x = x; p_c[top++].y = y+1; } } } if(top == 0) break; index = top; for(int i = 0; i \u0026lt; top; i++) { p[i].x = p_c[i].x; p[i].y = p_c[i].y; } } return map[m-1][n-1]; } }; ","date":"2015-05-22T01:18:11Z","permalink":"https://blog.coinidea.com/en/p/leetcode_62-unique-paths/","title":"[leetcode_62] Unique Paths"},{"content":"Rotate an n*n matrix 90 degrees clockwise. Additionally, can you do it in-place without allocating extra space?\nAC on the first try. Each position\u0026rsquo;s rotation only affects 4 positions in the matrix. Just use a single tmp variable and it\u0026rsquo;s done.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public: void MoveStep(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;matrix,int i,int j,int n) { int x1 = i; int y1 = j; int x2 = y1; int y2 = n - x1; int x3 = n - x1; int y3 = n - y1; int x4 = n - y1; int y4 = x1; int tmp = matrix[x4][y4]; matrix[x4][y4] = matrix[x3][y3]; matrix[x3][y3] = matrix[x2][y2]; matrix[x2][y2] = matrix[x1][y1]; matrix[x1][y1] = tmp; } void rotate(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;matrix) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. int length = matrix.size(); int n = length / 2; if(length % 2 == 0) { for(int i = 0; i \u0026lt; n; i++) { for(int j = 0; j \u0026lt; n; j++) { MoveStep(matrix, i, j, length-1); } } } else { for(int i = 0; i \u0026lt; n; i++) { for(int j = 0; j \u0026lt;= n; j++) { MoveStep(matrix, i, j, length-1); } } } } }; ","date":"2015-05-22T01:14:33Z","permalink":"https://blog.coinidea.com/en/p/leetcode_48-rotate-image/","title":"[leetcode_48] Rotate Image"},{"content":"Given n numbers where every number appears three times except one which appears only once, find that single number (in linear time and space).\nI\u0026rsquo;m sure everyone knows the two-number version — just use XOR.\nInitially I used a map to solve it, but that didn\u0026rsquo;t feel like it met the problem\u0026rsquo;s intent. After reading others\u0026rsquo; approaches, I realized it\u0026rsquo;s a variation of the same idea. I feel like I need to improve at generalizing solutions and analyzing problems.\nThe purpose of XOR is to count the number of 1s at each bit position, and reset to zero when the count reaches two.\nSimilarly, for three numbers, we reset to zero when the count reaches three.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public: int singleNumber(int A[], int n) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. int now = A[0]; int one = now; int two = 0; int three = 0; for(int i = 1; i \u0026lt; n; i++) { int input = A[i]; int in1 = one \u0026amp; input; one = one ^ input; int in2 = two \u0026amp; in1; two = two ^ in1; one = one ^ in2; } return one ^ two; } }; ","date":"2015-05-21T08:25:03Z","permalink":"https://blog.coinidea.com/en/p/leetcode_137-single-number-ii/","title":"[leetcode_137] Single Number II"},{"content":"Given a number n, generate all combinations of n pairs of parentheses.\nFor example, n=2: (()), ()()\nThis problem can be solved by backtracking through all possible cases:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public: vector\u0026lt;string\u0026gt; ans; void genStep(string \u0026amp;item,int n,int countLeft,int countRight) { if(countLeft == n \u0026amp;\u0026amp; countRight == n) { ans.push_back(item); return; } if(countLeft \u0026lt; n) { countLeft++; item.insert(item.length(),\u0026#34;(\u0026#34;); genStep(item,n,countLeft,countRight); countLeft--; item = item.erase(item.length()-1,1); } if(countRight \u0026lt; n \u0026amp;\u0026amp; countLeft \u0026gt; countRight) { countRight++; item.insert(item.length(),\u0026#34;)\u0026#34;); genStep(item,n,countLeft,countRight); countRight--; item = item.erase(item.length()-1,1); } } vector\u0026lt;string\u0026gt; generateParenthesis(int n) { ans.clear(); if(n == 0)return ans; int countLeft = 1; int countRight = 0; string item = \u0026#34;(\u0026#34;; genStep(item,n,countLeft,countRight); return ans; } }; ","date":"2015-05-21T08:23:53Z","permalink":"https://blog.coinidea.com/en/p/leetcode_22-generate-parentheses/","title":"[leetcode_22] Generate Parentheses"},{"content":"This problem was frustrating — no special judge allowed. So I initially wrote a solution that got WA. They said sorry, no special judge, so I adjusted based on the sample output.\nThe idea is:\n1\nPrepend (or append) (0, 1), (1, 0), (0, 1), (1, 0), (0, 1), (1, 0)\u0026hellip; to each number in the sequence [as shown in the sample]. Each number generates two new numbers. This ensures only one bit changes at a time, because the numbers from the previous round follow the pattern. So there won\u0026rsquo;t be any issues.\nHere are both versions of the code:\nWA code (I believe it should pass):\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public: vector\u0026lt;int\u0026gt; grayCode(int n) { // Note: The Solution object is instantiated only once and is reused by each test case. vector\u0026lt;int\u0026gt; seq; seq.clear(); if(n == 0) { seq.push_back(0); return seq; } for(int i = 0;i \u0026lt; n;i++) { if(i == 0) { seq.push_back(0); seq.push_back(1); } else { vector\u0026lt;int\u0026gt;seq_copy; seq_copy.clear(); int increase = (int)pow(2.0,i); int state = 0; for(int j = 0;j \u0026lt; seq.size();j++) { if(state == 0) { seq_copy.push_back(seq[j] + 0); seq_copy.push_back(seq[j] + increase); state = 1; } else if(state == 1) { seq_copy.push_back(seq[j] + increase); seq_copy.push_back(seq[j] + 0); state = 0; } } seq.clear(); for(int j = 0;j \u0026lt; seq_copy.size();j++) { seq.push_back(seq_copy[j]); } } } return seq; } }; AC code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class Solution { public: vector\u0026lt;int\u0026gt; grayCode(int n) { // Note: The Solution object is instantiated only once and is reused by each test case. vector\u0026lt;int\u0026gt; seq; seq.clear(); if(n == 0) { seq.push_back(0); return seq; } for(int i = 0;i \u0026lt; n;i++) { if(i == 0) { seq.push_back(0); seq.push_back(1); } else { vector\u0026lt;int\u0026gt;seq_copy; seq_copy.clear(); int state = 0; for(int j = 0;j \u0026lt; seq.size();j++) { if(state == 0) { seq_copy.push_back((seq[j]\u0026lt;\u0026lt;1) + 0); seq_copy.push_back((seq[j]\u0026lt;\u0026lt;1)+1); state = 1; } else if(state == 1) { seq_copy.push_back((seq[j]\u0026lt;\u0026lt;1)+1); seq_copy.push_back((seq[j]\u0026lt;\u0026lt;1) + 0); state = 0; } } seq.clear(); for(int j = 0;j \u0026lt; seq_copy.size();j++) { seq.push_back(seq_copy[j]); } } } return seq; } }; ","date":"2015-05-21T08:22:35Z","permalink":"https://blog.coinidea.com/en/p/leetcode_89-gray-code/","title":"[leetcode_89] Gray Code"},{"content":"This problem is essentially a simulation problem — swap ListNode nodes in pairs, based on nodes rather than values. It\u0026rsquo;s fairly simple, but I struggled with it for quite a while. Got AC on the first try, but I feel like my code never looks elegant and lacks reusability. My logic needs improvement. Still need to keep working hard.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *swapPairsStep(ListNode *head, int PairsNum) { ListNode *now = head; ListNode *before; for (int i = 0; i \u0026lt; PairsNum; i++) { now = now-\u0026gt;next; before = now; now = now-\u0026gt;next; } if (PairsNum == 0) { ListNode *tmp = now-\u0026gt;next; now-\u0026gt;next = now-\u0026gt;next-\u0026gt;next; tmp-\u0026gt;next = now; return tmp; } else { ListNode *tmp = now-\u0026gt;next; now-\u0026gt;next = now-\u0026gt;next-\u0026gt;next; tmp-\u0026gt;next = now; before-\u0026gt;next = tmp; } return head; } bool IsCheck(ListNode *head, int PairsNum) { ListNode *now = head; for (int i = 0; i \u0026lt; PairsNum; i++) { now = now-\u0026gt;next; now = now-\u0026gt;next; } if (now != NULL \u0026amp;\u0026amp; now-\u0026gt;next != NULL) { return true; } else { return false; } } ListNode *swapPairs(ListNode *head) { // Note: The Solution object is instantiated only once and is reused by each test case. int num = 0; while (IsCheck(head, num)) { head = swapPairsStep(head, num); num++; } return head; } }; ","date":"2015-05-21T08:20:37Z","permalink":"https://blog.coinidea.com/en/p/leetcode_24-swap-nodes-in-pairs/","title":"[leetcode_24] Swap Nodes in Pairs"},{"content":"Watch out for out-of-bounds issues when the input is empty.\nBinary split each time \u0026ndash; since the array is sorted, use the midpoint as the root.\nApply the same logic recursively to subtrees.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public: TreeNode *sortedArrayToBST(vector\u0026lt;int\u0026gt; \u0026amp;num) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. if(num.size() \u0026lt;= 0) return NULL; int size = num.size()-1; int mid = size / 2; TreeNode * root = new TreeNode(num[mid]); TreeNode * left = GetNode(num,0,mid-1); TreeNode * right = GetNode(num,mid+1,size); root-\u0026gt;left = left; root-\u0026gt;right = right; return root; } TreeNode *GetNode(vector\u0026lt;int\u0026gt; \u0026amp;num,int a,int b) { if(a \u0026gt; b) { return NULL; } int mid = a + (b - a) / 2; TreeNode * node = new TreeNode(num[mid]); TreeNode * left = GetNode(num,a,mid-1); TreeNode * right = GetNode(num,mid+1,b); node-\u0026gt;left = left; node-\u0026gt;right = right; return node; } }; ","date":"2015-05-21T08:17:25Z","permalink":"https://blog.coinidea.com/en/p/leetcode_108convert-sorted-array-to-binary-search-tree/","title":"[leetcode_108]Convert Sorted Array to Binary Search Tree"},{"content":"Determine whether a tree is a balanced binary tree.\nAC on the first try. Code below (I originally thought it would TLE):\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public: bool ans; bool isBalanced(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. ans = true; if(root == NULL) return ans; Calc(root); return ans; } int Calc(TreeNode *node) { if(node == NULL) return 0; int left = Calc(node-\u0026gt;left) + 1; int right = Calc(node-\u0026gt;right) + 1; if(abs(left - right) \u0026gt; 1) { ans = false; } if(left \u0026gt; right) return left; else return right; } }; ","date":"2015-05-21T08:16:19Z","permalink":"https://blog.coinidea.com/en/p/leetcode_110balanced-binary-tree/","title":"[leetcode_110]Balanced Binary Tree"},{"content":"Three colors: red, white, and blue, represented by 0, 1, and 2 respectively.\nGiven an array of 0s, 1s, and 2s, sort it \u0026ndash; but you cannot use any built-in sorting library.\nThe approach is to traverse the array, count the occurrences of 0, 1, and 2, then overwrite the original array accordingly.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public: void sortColors(int A[], int n) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. int count0 = 0; int count1 = 0; int count2 = 0; for(int i = 0; i \u0026lt; n; i++) { switch(A[i]) { case 0: count0++; break; case 1: count1++; break; case 2: count2++; break; } } for(int i = 0; i \u0026lt; count0; i++) { A[i] = 0; } for(int i = count0; i \u0026lt; count0 + count1; i++) { A[i] = 1; } for(int i = count0 + count1; i \u0026lt; count0 + count1 + count2; i++) { A[i] = 2; } } }; ","date":"2015-05-21T08:15:06Z","permalink":"https://blog.coinidea.com/en/p/leetcode_75sort-colors/","title":"[leetcode_75]Sort Colors"},{"content":"Given a binary tree and a number sum, compute the sum along each path from the root to every leaf node. Determine whether any leaf node\u0026rsquo;s path sum equals sum.\nThis problem can be solved with BFS by enumerating all paths, but watch the edge cases: it must be a leaf node, and consider the cases where the root has no children or is null.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Solution { public: bool hasPathSum(TreeNode *root, int sum) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. TreeNode ** seq = new TreeNode*[10000]; TreeNode ** rseq = new TreeNode*[10000]; if(root == NULL) return false; else { if(root-\u0026gt;left == NULL \u0026amp;\u0026amp; root-\u0026gt;right == NULL) { if(root-\u0026gt;val == sum) return true; else return false; } int index = 0; seq[index++] = root; while(true) { int top = index; index = 0; for(int i = 0;i \u0026lt; top;i++) { if(seq[i] != NULL) { if(seq[i]-\u0026gt;left != NULL) { seq[i]-\u0026gt;left-\u0026gt;val += seq[i]-\u0026gt;val; rseq[index++] = seq[i]-\u0026gt;left; if(seq[i]-\u0026gt;left-\u0026gt;val == sum \u0026amp;\u0026amp; seq[i]-\u0026gt;left-\u0026gt;left == NULL \u0026amp;\u0026amp; seq[i]-\u0026gt;left-\u0026gt;right == NULL) return true; } if(seq[i]-\u0026gt;right != NULL) { seq[i]-\u0026gt;right-\u0026gt;val += seq[i]-\u0026gt;val; rseq[index++] = seq[i]-\u0026gt;right; if(seq[i]-\u0026gt;right-\u0026gt;val == sum \u0026amp;\u0026amp; seq[i]-\u0026gt;right-\u0026gt;left == NULL \u0026amp;\u0026amp; seq[i]-\u0026gt;right-\u0026gt;right == NULL) return true; } } } if(index == 0) break; for(int i = 0;i \u0026lt; index;i++) { seq[i] = rseq[i]; } } return false; } } }; ","date":"2015-05-21T08:13:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode_112path-sum/","title":"[leetcode_112]Path Sum"},{"content":"Output the binary tree levels from bottom to top.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt; \u0026gt; levelOrderBottom(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; result; result.clear(); TreeNode **seq = new TreeNode *[1000]; TreeNode **rseq = new TreeNode *[1000]; int index = 0; seq[index++] = root; while(true) { int top = index; index = 0; vector\u0026lt;int\u0026gt; tmp; tmp.clear(); for(int i = 0 ;i\u0026lt; top;i++) { if(seq[i] != NULL) { tmp.push_back(seq[i]-\u0026gt;val); if (seq[i]-\u0026gt;left != NULL) { rseq[index++] = seq[i]-\u0026gt;left; } if (seq[i]-\u0026gt;right != NULL) { rseq[index++] = seq[i]-\u0026gt;right; } } } if(tmp.size() \u0026gt; 0) result.push_back(tmp); if(index == 0) break; for(int i = 0;i \u0026lt; index;i++) { seq[i] = rseq[i]; } } vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; ans.clear(); for(int i = result.size() - 1;i \u0026gt;= 0;i--) { ans.push_back(result[i]); } return ans; } }; ","date":"2015-05-21T08:12:31Z","permalink":"https://blog.coinidea.com/en/p/leetcode_107binary-tree-level-order-traversal-ii/","title":"[leetcode_107]Binary Tree Level Order Traversal II"},{"content":"Postorder traversal of a binary tree, with a focus on code quality. AC on the first try, no separate testing needed.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public: vector\u0026lt;int\u0026gt; postorderTraversal(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. vector\u0026lt;int\u0026gt; result; result.clear(); if (NULL != root) { Traversal(root-\u0026gt;left, result); Traversal(root-\u0026gt;right, result); result.push_back(root-\u0026gt;val); } return result; } void Traversal(TreeNode * now, vector\u0026lt;int\u0026gt;\u0026amp; result) { if (NULL != now) { Traversal(now-\u0026gt;left, result); Traversal(now-\u0026gt;right, result); result.push_back(now-\u0026gt;val); } } }; ","date":"2015-05-21T08:11:21Z","permalink":"https://blog.coinidea.com/en/p/leetcode_145binary-tree-postorder-traversal/","title":"[leetcode_145]Binary Tree Postorder Traversal"},{"content":"Left-root-right, inorder traversal.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public: vector\u0026lt;int\u0026gt; result; vector\u0026lt;int\u0026gt; inorderTraversal(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. result.clear(); if(root == NULL) return result; Traversal(root-\u0026gt;left); result.push_back(root-\u0026gt;val); Traversal(root-\u0026gt;right); return result; } void Traversal(TreeNode * now) { if(now == NULL) return ; Traversal(now-\u0026gt;left); result.push_back(now-\u0026gt;val); Traversal(now-\u0026gt;right); } }; ","date":"2015-05-21T08:10:09Z","permalink":"https://blog.coinidea.com/en/p/leetcode_94binary-tree-inorder-traversal/","title":"[leetcode_94]Binary Tree Inorder Traversal"},{"content":"BFS approach. The earlier TLE was because I had written a DFS instead.\nAfter switching, AC on the first try. Code below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 class Solution { public: int rows; int cols; int minnow; int minPathSum(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;grid) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. rows = grid.size()-1; cols = grid[0].size()-1; vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; copygrid(grid.size()); int sum = 0; for(int i = 0; i \u0026lt; grid.size(); i++) { for(int j = 0; j \u0026lt; grid[0].size(); j++) { sum += grid[i][j]; } } for(int i = 0; i \u0026lt; grid.size(); i++) { vector\u0026lt;int\u0026gt; tmp(grid[0].size()); for(int j = 0; j \u0026lt; grid[0].size(); j++) { tmp[j] = sum; } copygrid[i] = tmp; } copygrid[0][0] = grid[0][0]; int px[10000], py[10000]; int cpx[20000], cpy[20000]; int index = 0; px[index] = 0; py[index++] = 0; while(true) { int top = index; index = 0; for(int i = 0; i \u0026lt; top; i++) { int x = px[i]; int y = py[i]; if(x + 1 \u0026lt;= rows) { if(copygrid[x][y] + grid[x+1][y] \u0026lt; copygrid[x+1][y]) { copygrid[x+1][y] = copygrid[x][y] + grid[x+1][y]; cpx[index] = x+1; cpy[index] = y; index++; } } if(y + 1 \u0026lt;= cols) { if(copygrid[x][y] + grid[x][y+1] \u0026lt; copygrid[x][y+1]) { copygrid[x][y+1] = copygrid[x][y] + grid[x][y+1]; cpx[index] = x; cpy[index] = y+1; index++; } } } if(index == 0) break; for(int i = 0; i \u0026lt; index; i++) { px[i] = cpx[i]; py[i] = cpy[i]; } } return copygrid[rows][cols]; } }; ","date":"2015-05-21T08:08:44Z","permalink":"https://blog.coinidea.com/en/p/leetcode_64minimum-path-sum/","title":"[leetcode_64]Minimum Path Sum"},{"content":"Merge array B into array A. Both A and B are originally sorted, and the result should remain sorted.\nInsertion sort.\nThough I wonder why my insertion sort implementation turned out so verbose.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { public: void merge(int A[], int m, int B[], int n) { // Note: The Solution object is instantiated only once and is reused by each test case. for(int i = 0;i \u0026lt; n;i++) { Insert(A,m+i,B[i]); } } void Insert(int A[],int lengthA,int val) { if(lengthA == 0) { A[lengthA] = val; return; } if(val \u0026gt; A[lengthA-1]) { A[lengthA] = val; return ; } int i; for(i = lengthA-1;i \u0026gt;= 0;i--) { if(val \u0026lt; A[i]) { A[i+1] = A[i]; } else { A[i+1] = val; break; } } if(i == -1) { A[0] = val; } } }; ","date":"2015-05-21T08:07:29Z","permalink":"https://blog.coinidea.com/en/p/leetcode_88merge-sorted-array/","title":"[leetcode_88]Merge Sorted Array"},{"content":"Merge two sorted singly linked lists.\nAC on the first try.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 class Solution { public: ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { // Note: The Solution object is instantiated only once and is reused by each test case. if(l1 == NULL) return l2; if(l2 == NULL) return l1; int val; if(l1-\u0026gt;val \u0026lt; l2-\u0026gt;val) { val = l1-\u0026gt;val; l1 = l1-\u0026gt;next; } else { val = l2-\u0026gt;val; l2 = l2 -\u0026gt;next; } ListNode * l = new ListNode(val); ListNode * lcopy = l; int flag = 0; while(true) { if(l1 == NULL) { flag = 1; break; } if(l2 == NULL) { flag = 2; break; } if(l1-\u0026gt;val \u0026lt; l2-\u0026gt;val) { val = l1-\u0026gt;val; l1 = l1-\u0026gt;next; } else { val = l2-\u0026gt;val; l2 = l2 -\u0026gt;next; } ListNode * tmp = new ListNode(val); lcopy-\u0026gt;next = tmp; lcopy = lcopy-\u0026gt;next; } if(flag == 1) { while(l2 != NULL) { val = l2-\u0026gt;val; l2 = l2-\u0026gt;next; ListNode * tmp = new ListNode(val); lcopy-\u0026gt;next = tmp; lcopy = lcopy-\u0026gt;next; } } if(flag == 2) { while(l1 != NULL) { val = l1-\u0026gt;val; l1 = l1-\u0026gt;next; ListNode * tmp = new ListNode(val); lcopy-\u0026gt;next = tmp; lcopy = lcopy-\u0026gt;next; } } return l; } }; ","date":"2015-05-21T08:05:52Z","permalink":"https://blog.coinidea.com/en/p/leetcode_21merge-two-sorted-lists/","title":"[leetcode_21]Merge Two Sorted Lists"},{"content":"I recall reading in \u0026ldquo;Programming Pearls\u0026rdquo; that you should first have an idea \u0026ndash; an \u0026ldquo;aha!\u0026rdquo; moment of inspiration \u0026ndash; then find a suitable data structure, and finally write the code. That\u0026rsquo;s my understanding of the process.\nAs for this problem, well\u0026hellip; ever since I learned about binary tree serialization, I\u0026rsquo;ve been using it everywhere. But here it kept giving me WA \u0026ndash; 188 out of 190 test cases passed.\nFrustrating.\nAfter struggling for a day, I couldn\u0026rsquo;t resist and looked at other people\u0026rsquo;s approaches. So little code! Painful.\nIt\u0026rsquo;s actually just recursion. The key insight during recursion is to mirror: compare the left child\u0026rsquo;s left subtree with the right child\u0026rsquo;s right subtree, and vice versa.\nCode below. After changing the approach, AC on the first try.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public: bool isSymmetric(TreeNode *root) { // Note: The Solution object is instantiated only once and is reused by each test case. if(root == NULL) return true; return CheckEqual(root-\u0026gt;left,root-\u0026gt;right); } bool CheckEqual(TreeNode * left,TreeNode * right) { if(left == NULL \u0026amp;\u0026amp; right == NULL) return true; if((left == NULL \u0026amp;\u0026amp; right != NULL)||(left != NULL \u0026amp;\u0026amp; right == NULL)) return false; if(left-\u0026gt;val != right-\u0026gt;val) return false; return CheckEqual(left-\u0026gt;left,right-\u0026gt;right)\u0026amp;\u0026amp;CheckEqual(left-\u0026gt;right,right-\u0026gt;left); } }; ","date":"2015-05-21T08:04:08Z","permalink":"https://blog.coinidea.com/en/p/leetcode_101symmetric-tree/","title":"[leetcode_101]Symmetric Tree"},{"content":"Since it\u0026rsquo;s a binary search tree, we iterate based on choosing different roots.\nCode below. AC on the first try, though it took me a while to figure it out.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public: int numTrees(int n) { // Note: The Solution object is instantiated only once and is reused by each test case. if(n == 1)return 1; if(n == 2)return 2; if(n == 3)return 5; int *num = new int[n + 1]; num[0] = 1; num[1] = 1; num[2] = 2; num[3] = 5; for(int i = 4;i \u0026lt;= n;i++) { num[i] = 0; for(int j = 1;j \u0026lt;= i;j++) { num[i] += num[j-1]*num[i-j]; } } return num[n]; } }; ","date":"2015-05-21T08:02:33Z","permalink":"https://blog.coinidea.com/en/p/leetcode_96unique-binary-search-trees/","title":"[leetcode_96]Unique Binary Search Trees"},{"content":"Ugh. I got AC using recursion but it didn\u0026rsquo;t count as accepted \u0026ndash; the problem wasn\u0026rsquo;t checked off. As someone with a bit of OCD, that\u0026rsquo;s painful. I\u0026rsquo;ll think of another approach later.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public: vector\u0026lt;int\u0026gt; ans; vector\u0026lt;int\u0026gt; preorderTraversal(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. ans.clear(); fun(root); return ans; } void fun(TreeNode *root) { if (root != NULL) { ans.push_back(root-\u0026gt;val); if (root-\u0026gt;left != NULL) fun(root-\u0026gt;left); if (root-\u0026gt;right != NULL) fun(root-\u0026gt;right); } } }; ","date":"2015-05-21T08:01:09Z","permalink":"https://blog.coinidea.com/en/p/leetcode_144binary-tree-preorder-traversal/","title":"[leetcode_144]Binary Tree Preorder Traversal"},{"content":"Binary tree serialization by level.\nAC on the first try. Code below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt; \u0026gt; levelOrder(TreeNode *root) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; ans.clear(); TreeNode ** seq = new TreeNode *[100000]; TreeNode ** rseq = new TreeNode *[100000]; int index = 0; seq[index++] = root; int top = index; while(true) { index = 0; vector\u0026lt;int\u0026gt; tmp; tmp.clear(); int flag = 0; for(int i = 0;i \u0026lt; top;i++) { if(seq[i] != NULL) { if(seq[i]-\u0026gt;left != NULL) rseq[index++] = seq[i]-\u0026gt;left; if(seq[i]-\u0026gt;right != NULL) rseq[index++] = seq[i]-\u0026gt;right; tmp.push_back(seq[i]-\u0026gt;val); flag = 1; } } if(flag == 1) ans.push_back(tmp); else break; if(index == 0) break; for(int i = 0;i \u0026lt; index;i++) { seq[i] = rseq[i]; } top = index; } return ans; } }; ","date":"2015-05-21T07:59:36Z","permalink":"https://blog.coinidea.com/en/p/leetcode_102binary-tree-level-order-traversal/","title":"[leetcode_102]Binary Tree Level Order Traversal"},{"content":"This problem gave me a new understanding of binary tree serialization.\n1\n2 3\n4 5 6\nA tree like this is serialized as: 1 2 3 4 # 5 6\nWhich means:\n1 | 2 3 | 4 # 5 6\nrepresenting the first, second, and third levels respectively.\nWith this approach, we just need to enumerate level by level.\nWatch out for out-of-bounds issues. Code below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution { public: void connect(TreeLinkNode *root) { // Note: The Solution object is instantiated only once and is reused by each test case. int height = -1; TreeLinkNode * rootheight = root; while(rootheight != NULL) { height++; rootheight = rootheight-\u0026gt;left; } int NumOfNodes = (int)pow(2.0,height+1) - 1; TreeLinkNode ** LinkNodeArray = new TreeLinkNode *[NumOfNodes]; int index = 0; LinkNodeArray[index++] = root; int bottom = 0; int top = index; while(true) { if(bottom == top) break; for(int i = bottom;i \u0026lt; top;i++) { if(LinkNodeArray[i] == NULL) continue; if(i == top-1) { LinkNodeArray[i] -\u0026gt;next = NULL; if(LinkNodeArray[i]-\u0026gt;left != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;left; if(LinkNodeArray[i]-\u0026gt;right != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;right; } else { LinkNodeArray[i] -\u0026gt;next = LinkNodeArray[i+1]; if(LinkNodeArray[i]-\u0026gt;left != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;left; if(LinkNodeArray[i]-\u0026gt;right != NULL) LinkNodeArray[index++] = LinkNodeArray[i]-\u0026gt;right; } } bottom = top; top = index; } } }; ","date":"2015-05-21T03:03:31Z","permalink":"https://blog.coinidea.com/en/p/leetcode_116populating-next-right-pointers-in-each-node/","title":"[leetcode_116]Populating Next Right Pointers in Each Node"},{"content":"Two binary searches, AC on the first try. Watch out for out-of-bounds issues.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 using namespace std; class Solution { public: bool searchMatrix(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;matrix, int target) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. if(matrix.size() \u0026lt;= 0) return false; if(target \u0026gt; matrix[matrix.size()-1][matrix[0].size()-1]) return false; vector\u0026lt;int\u0026gt;cols(matrix.size()); for(int i = 0; i \u0026lt; matrix.size(); i++) { cols[i] = matrix[i][matrix[0].size()-1]; } int colindex = bsearch(0, (int)(matrix.size()), cols, target); if(colindex == -1) return true; int rowindex = bsearch(0, (int)(matrix[colindex].size()), matrix[colindex], target); if(rowindex == -1) return true; return false; } int bsearch(int left, int right, vector\u0026lt;int\u0026gt; seq, int target) { if(left \u0026gt; right) { return right + 1; } int mid = (left + right) / 2; if(seq[mid] == target) { return -1; } else if(seq[mid] \u0026lt; target) { return bsearch(mid+1, right, seq, target); } else { return bsearch(left, mid-1, seq, target); } } }; ","date":"2015-05-21T03:01:41Z","permalink":"https://blog.coinidea.com/en/p/leetcode_74search-a-2d-matrix/","title":"[leetcode_74]Search a 2D Matrix"},{"content":"This problem asks you to determine whether a singly linked list has a cycle, without using extra space.\nAt first I really didn\u0026rsquo;t know how to solve it, so I looked at other people\u0026rsquo;s solutions.\nThe idea is to use two pointers: one advances one step at a time, the other advances two steps. If they reach NULL without ever being equal, there is no cycle. If they become equal, a cycle exists.\nCode below. I honestly feel my pointer and linked list skills are pretty weak.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public: bool hasCycle(ListNode *head) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. ListNode * step1 = head; ListNode * step2 = head; while(true) { if(step1 == NULL) { return false; } step1 = step1-\u0026gt;next; if(step2 == NULL || step2-\u0026gt;next == NULL) { return false; } step2 = step2-\u0026gt;next-\u0026gt;next; if(step1 == step2) { return true; } } } }; ","date":"2015-05-21T03:00:15Z","permalink":"https://blog.coinidea.com/en/p/leetcode_141linked-list-cycle/","title":"[leetcode_141]Linked List Cycle"},{"content":"Note that k is 0-indexed.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public: vector\u0026lt;int\u0026gt; getRow(int rowIndex) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. rowIndex++; vector\u0026lt;int\u0026gt; ans(rowIndex); if(rowIndex == 1) { ans[0] = 1; } else if(rowIndex == 2) { ans[0] = 1; ans[1] = 1; } else { ans[0] = 1; ans[1] = 2; ans[2] = 1; for(int i = 4;i \u0026lt;= rowIndex;i++) { ans[0] = 1; ans[i-1] = 1; for(int j = i-2;j \u0026gt;= 1;j--) { ans[j] = ans[j-1] + ans[j]; } } } return ans; } }; ","date":"2015-05-21T02:53:53Z","permalink":"https://blog.coinidea.com/en/p/leetcode_119pascals-triangle-ii/","title":"[leetcode_119]Pascal's Triangle II"},{"content":"Output a spirally growing matrix. AC on the second try \u0026ndash; watch out for the n=0 case.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt; \u0026gt; generateMatrix(int n) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans(n); if(n == 0) { ans.clear(); return ans; } int **map = new int*[n]; for(int i = 0; i \u0026lt; n; i++) { map[i] = new int[n]; } int val = 1; int x = 0; int y = 0; int dir = 1; // 1 right 2 down 3 left 4 up int r1 = -1; int r2 = n; int l1 = -1; int l2 = n; while(true) { map[x][y] = val; switch(dir) { case 1: y++; if(y == l2) { dir = 2; y--; x++; r1++; } break; case 2: x++; if(x == r2) { dir = 3; x--; y--; l2--; } break; case 3: y--; if(y == l1) { dir = 4; y++; x--; r2--; } break; case 4: x--; if(x == r1) { dir = 1; x++; y++; l1++; } break; } if(val == n*n) break; val++; } for(int i = 0; i \u0026lt; n; i++) { vector\u0026lt;int\u0026gt; tmp(n); for(int j = 0; j \u0026lt; n; j++) { tmp[j] = map[i][j]; } ans[i] = tmp; } return ans; } }; ","date":"2015-05-21T02:51:54Z","permalink":"https://blog.coinidea.com/en/p/leetcode_59-spiral-matrix-ii/","title":"[leetcode_59] Spiral Matrix II"},{"content":"Simple array or vector manipulation, AC on the first try.\nFind the relationship between adjacent rows.\nCode below:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; generate(int numRows) { // Note: The Solution object is instantiated only once and is reused by each test case. vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans(numRows); for(int i = 1; i \u0026lt;= numRows; i++) { vector\u0026lt;int\u0026gt; tmp(i); if(i == 1) { tmp[0] = 1; ans[i-1] = tmp; continue; } if(i == 2) { tmp[0] = 1; tmp[1] = 1; ans[i-1] = tmp; continue; } tmp[0] = 1; tmp[i-1] = 1; for(int j = 1; j \u0026lt; i-1; j++) { tmp[j] = ans[i-2][j-1] + ans[i-2][j]; } ans[i-1] = tmp; } return ans; } }; ","date":"2015-05-20T01:36:19Z","permalink":"https://blog.coinidea.com/en/p/leetcode_118pascals-triangle/","title":"[leetcode_118]Pascal's Triangle"},{"content":"Simple DP problem. Accepted on the first try. Here is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution { public: int minimumTotal(vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; \u0026amp;triangle) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. for(int i = triangle.size()-2; i \u0026gt;= 0; i--) { for(int j = 0; j \u0026lt; triangle[i].size(); j++) { if(triangle[i][j] + triangle[i+1][j] \u0026lt; triangle[i][j] + triangle[i+1][j+1]) { triangle[i][j] = triangle[i][j] + triangle[i+1][j]; } else { triangle[i][j] = triangle[i][j] + triangle[i+1][j+1]; } } } return triangle[0][0]; } }; ","date":"2015-05-20T01:34:23Z","permalink":"https://blog.coinidea.com/en/p/leetcode_120triangle/","title":"[leetcode_120]Triangle"},{"content":"Find the contiguous subarray with the largest sum.\nDid not get Accepted on the first try \u0026ndash; my coding skills really need improvement. Pay attention to boundary conditions. I feel this code is not great.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution { public: int maxSubArray(int A[], int n) { // Note: The Solution object is instantiated only once and is reused by each test case. int sum = 0; if(n == 1) { return A[0]; } int * value = new int[n]; if(A[0] \u0026lt;= 0) value[0] = 0; else { value[0] = A[0]; if(value[0] \u0026gt; sum) sum = value[0]; } for(int i = 1;i \u0026lt; n;i++) { if(A[i] + value[i-1] \u0026gt; 0) { value[i] = A[i] + value[i-1]; if(value[i] \u0026gt; sum) sum = value[i]; } else { value[i] = 0; } } if(sum == 0) { sum = -999999999; for(int i = 0;i \u0026lt; n;i++) { if(A[i] \u0026gt; sum) sum = A[i]; } } return sum; } }; ","date":"2015-05-20T01:33:07Z","permalink":"https://blog.coinidea.com/en/p/leetcode_53maximum-subarray/","title":"[leetcode_53]Maximum Subarray"},{"content":"I used to think this problem was really hard, but the acceptance rate was so high. I was frustrated wondering why I couldn\u0026rsquo;t solve it.\nThen yesterday, after solving Part I on a whim, everything suddenly clicked.\nThe problem requires that you must buy before you sell, and you can only buy again after selling. You can make multiple transactions. What is the maximum profit?\nThe solution: compute the day-to-day price differences, then sum up all the positive differences.\nAccepted on the first try:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public: int maxProfit(vector\u0026lt;int\u0026gt; \u0026amp;prices) { // Note: The Solution object is instantiated only once and is reused by each test case. int sum = 0; if(prices.size() \u0026lt;= 0) return sum; vector\u0026lt;int\u0026gt; dis(prices.size()-1); for(int i = 1;i \u0026lt; prices.size();i++) { dis[i-1] = prices[i] - prices[i-1]; } for(int i = 0;i \u0026lt; dis.size();i++) { if(dis[i] \u0026gt; 0) { sum += dis[i]; } } return sum; } }; ","date":"2015-05-20T01:31:40Z","permalink":"https://blog.coinidea.com/en/p/leetcode_122best-time-to-buy-and-sell-stock-ii/","title":"[leetcode_122]Best Time to Buy and Sell Stock II"},{"content":"Got TLE on the first attempt as expected. I realized that my duplicate checking was using linear time each time, which was too slow.\nThis is where a data structure called map comes in handy.\nAfter switching to map, it passed in 888ms.\nI still need to study and practice map usage more. Here is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include \u0026lt;map\u0026gt; using namespace std; class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; map\u0026lt;vector\u0026lt;int\u0026gt;, int\u0026gt; markmap; bool flag[100000]; int sum; vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; permuteUnique(vector\u0026lt;int\u0026gt; \u0026amp;num) { // Note: The Solution object is instantiated only once and is reused by each test case. ans.clear(); markmap.clear(); sum = num.size(); for(int i = 0; i \u0026lt; sum; i++) { flag[i] = false; } for(int i = 0; i \u0026lt; sum; i++) { flag[i] = true; vector\u0026lt;int\u0026gt; tmp(sum); tmp[0] = i; fun(tmp, 1, num); flag[i] = false; } return ans; } void fun(vector\u0026lt;int\u0026gt; \u0026amp;tmp, int k, vector\u0026lt;int\u0026gt; \u0026amp;num) { if(k \u0026gt;= sum) { vector\u0026lt;int\u0026gt; numtmp(sum); for(int i = 0; i \u0026lt; sum; i++) { numtmp[i] = num[tmp[i]]; } map\u0026lt;vector\u0026lt;int\u0026gt;, int\u0026gt;::iterator l_it = markmap.find(numtmp); if(markmap.empty() || l_it == markmap.end()) { ans.push_back(numtmp); markmap[numtmp] = 590; } return; } for(int i = 0; i \u0026lt; sum; i++) { if(!flag[i]) { flag[i] = true; tmp[k] = i; fun(tmp, k + 1, num); flag[i] = false; } } } }; ","date":"2015-05-20T01:30:13Z","permalink":"https://blog.coinidea.com/en/p/leetcode_47permutations-ii/","title":"[leetcode_47]Permutations II"},{"content":"Want to know why I almost gave up later? It was because I got stuck on the 3Sum problem, which prevented me from picking high-acceptance-rate problems to work on. The 3Sum problem also kept giving me OLE!\nThe 3Sum problem asks: given a sequence, find all triplets whose sum equals zero.\nAt first I naively thought it would be as simple as the 2Sum problem with a greedy two-pointer approach. But no.\nMy approach:\nSort the array in O(n log n) Enumerate three cases: two negatives and one positive, three zeros, one negative and two positives O(n^2) complexity, using binary search for the third number This should actually be faster than strict O(n^2).\nI was worried about TLE from the start. But instead it gave me Output Limit Exceeded \u0026ndash; so frustrating.\nAfter modifying the code, finally Accepted:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 #include \u0026lt;algorithm\u0026gt; using namespace std; int cmp(int a,int b) { return a \u0026lt; b; } class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; threeSum(vector\u0026lt;int\u0026gt; \u0026amp;num) { // Note: The Solution object is instantiated only once and is reused by each test case. vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; ans.clear(); int *seq = new int[num.size()]; for(int i = 0; i \u0026lt; num.size(); i++) { seq[i] = num[i]; } sort(seq, seq + num.size(), cmp); int count0 = 0; int left = -1; int right = -1; for(int i = 0; i \u0026lt; num.size(); i++) { if(seq[i] == 0) { if(left == -1) { left = i - 1; } count0++; } if(seq[i] \u0026gt; 0) { if(left == -1) { left = i - 1; } if(right == -1) { right = i; break; } } } int index = 0; if(left == -1 || right == -1) { if(count0 \u0026gt;= 3) { vector\u0026lt;int\u0026gt; ivector(3, 0); ans.push_back(ivector); } return ans; } //two negatives and one positive for(int i = 0; i \u0026lt; left; i++) { for(int j = i + 1; j \u0026lt;= left; j++) { int a[3]; a[0] = seq[i]; a[1] = seq[j]; a[2] = (seq[i] + seq[j]) * (-1); if(bsearch(right, num.size() - 1, seq, a[2]) == true) { vector\u0026lt;int\u0026gt; ivector(a, a + 3); bool flag = false; for(int k = 0; k \u0026lt; ans.size(); k++) { if(ivector == ans[k]) { flag = true; break; } } if(flag == false) ans.push_back(ivector); } } } if(count0 \u0026gt;= 1) { for(int i = 0; i \u0026lt;= left; i++) { if(i \u0026gt;= 1) { if(seq[i] == seq[i - 1]) continue; } int a[3]; a[0] = seq[i]; a[1] = 0; a[2] = seq[i] * (-1); if(bsearch(right, num.size() - 1, seq, a[2]) == true) { vector\u0026lt;int\u0026gt; ivector(a, a + 3); bool flag = false; for(int k = 0; k \u0026lt; ans.size(); k++) { if(ivector == ans[k]) { flag = true; break; } } if(flag == false) ans.push_back(ivector); } } } //three zeros if(count0 \u0026gt;= 3) { vector\u0026lt;int\u0026gt; ivector(3, 0); ans.push_back(ivector); } //one negative and two positives for(int i = right; i \u0026lt; num.size() - 1; i++) { for(int j = i + 1; j \u0026lt; num.size(); j++) { if(i != j) { int a[3]; a[1] = seq[i]; a[2] = seq[j]; a[0] = (seq[i] + seq[j]) * (-1); if(bsearch(0, left, seq, a[0]) == true) { vector\u0026lt;int\u0026gt; ivector(a, a + 3); bool flag = false; for(int k = 0; k \u0026lt; ans.size(); k++) { if(ivector == ans[k]) { flag = true; break; } } if(flag == false) ans.push_back(ivector); } } } } return ans; } bool bsearch(int left, int right, int *num, int a) { if(left \u0026gt; right) return false; int mid = (left + right) / 2; if(num[mid] == a) return true; if(num[mid] \u0026gt; a) { return bsearch(left, mid - 1, num, a); } if(num[mid] \u0026lt; a) { return bsearch(mid + 1, right, num, a); } } }; ","date":"2015-05-19T04:53:43Z","permalink":"https://blog.coinidea.com/en/p/leetcode_153sum/","title":"[leetcode_15]3Sum"},{"content":"Generate all permutations of the input array and output them.\nI kept getting Output Limit Exceeded and couldn\u0026rsquo;t figure out why.\nI remembered asking a friend about it, and he said my output was larger than expected. The judge gave OLE after checking.\nThat felt even worse than getting TLE \u0026ndash; at least with TLE I could optimize my code!\nLater I wondered if there were duplicate elements in the array. I tried checking for duplicates before inserting into the vector, but still got OLE.\nFinally I gave up and looked at other people\u0026rsquo;s solutions. The approach was the same as mine.\nThen I suddenly noticed there\u0026rsquo;s a problem called Permutations II, which says the data may contain duplicates \u0026ndash; meaning this problem\u0026rsquo;s data should NOT have duplicates!\nLooking more carefully at others\u0026rsquo; code, I noticed something more professional: vector.clear().\nJust that one line was missing.\nAfter adding it \u0026ndash; Accepted!\nHere is the code (a bit rough):\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { public: vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; ans; bool flag[100000]; int sum; vector\u0026lt;vector\u0026lt;int\u0026gt;\u0026gt; permute(vector\u0026lt;int\u0026gt; \u0026amp;num) { // Note: The Solution object is instantiated only once and is reused by each test case. sum = num.size(); ans.clear(); for(int i = 0;i \u0026lt; sum;i++) { flag[i] = false; } for(int i = 0;i \u0026lt; sum;i++) { flag[i] = true; vector\u0026lt;int\u0026gt; tmp(sum); tmp[0] = i; fun(tmp,1,num); flag[i] = false; } return ans; } void fun(vector\u0026lt;int\u0026gt; \u0026amp;tmp,int k,vector\u0026lt;int\u0026gt; \u0026amp;num) { if(k \u0026gt;= sum) { vector\u0026lt;int\u0026gt; numtmp(sum); for(int i = 0;i \u0026lt; sum;i++) { numtmp[i] = num[tmp[i]]; } ans.push_back(numtmp); return ; } for(int i = 0;i \u0026lt; sum;i++) { if(!flag[i]) { flag[i] = true; tmp[k] = i; fun(tmp,k+1,num); flag[i] = false; } } } }; ","date":"2015-05-19T04:51:31Z","permalink":"https://blog.coinidea.com/en/p/leetcode_46permutations/","title":"[leetcode_46]Permutations"},{"content":"I honestly didn\u0026rsquo;t expect to solve this one on my own, and the process was quite a journey. Persistence pays off!\nThe problem is roughly: you are trading stocks and can only make one transaction (buy once, sell once). On which day should you buy and on which later day should you sell to maximize profit?\nI thought this would be easy \u0026ndash; just brute force it. Of course, that resulted in TLE.\nThen I racked my brain trying to figure out how to reduce the time complexity. Sorting? Greedy? It felt similar to the 2Sum problem, especially after drawing vertical lines on a graph.\nThen it hit me: the difference between consecutive days represents the price change. If I compute these differences and then find the maximum contiguous subarray sum, the problem is solved!\nI gave it a try and \u0026ndash; AC!\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public: int maxProfit(vector\u0026lt;int\u0026gt; \u0026amp;prices) { // Note: The Solution object is instantiated only once and is reused by each test case. int max = 0; if(prices.size() \u0026lt;= 1) return max; vector\u0026lt;int\u0026gt; dis(prices.size()-1); for(int i = 1;i \u0026lt; prices.size();i++) { dis[i-1] = prices[i] - prices[i-1]; } vector\u0026lt;int\u0026gt; value(dis.size()); for(int i = 0;i \u0026lt; dis.size();i++) { value[i] = dis[i]; } if(dis[0] \u0026lt; 0) value[0] = 0; else value[0] = dis[0]; for(int i = 1;i \u0026lt; value.size();i++) { if(value[i-1] + value[i] \u0026lt; 0) { value[i] = 0; } else { value[i] = value[i-1] + value[i]; } } for(int i = 0;i \u0026lt; value.size();i++) { if(value[i] \u0026gt; max) { max = value[i]; } } return max; } }; ","date":"2015-05-19T04:48:56Z","permalink":"https://blog.coinidea.com/en/p/leetcode_121best-time-to-buy-and-sell-stock/","title":"[leetcode_121]Best Time to Buy and Sell Stock"},{"content":"Big number addition. Accepted on the first try. The solution may not be optimal.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public: vector\u0026lt;int\u0026gt; plusOne(vector\u0026lt;int\u0026gt; \u0026amp;digits) { // Note: The Solution object is instantiated only once and is reused by each test case. vector\u0026lt;int\u0026gt; ans(digits.size()+1); for(int i = 0;i \u0026lt; ans.size();i++) { ans[i] = 0; } int in = 1; for(int i = digits.size() - 1;i \u0026gt;= 0;i--) { int now = digits[i] + in; ans[i+1] = now % 10; in = now / 10; } ans[0] = in; if(ans[0] != 0) return ans; else { vector\u0026lt;int\u0026gt; result(digits.size()); for(int i = 0;i \u0026lt; digits.size();i++) { result[i] = ans[i+1]; } return result; } } }; ","date":"2015-05-19T04:45:51Z","permalink":"https://blog.coinidea.com/en/p/leetcode_66plus-one/","title":"[leetcode_66]Plus One"},{"content":"Remove duplicate elements from a sorted array without allocating extra space.\nUse insertion sort-style swapping to move duplicates to the end of the array. Somewhat similar to the previous problem.\nAccepted on the first try. Here is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public: int removeDuplicates(int A[], int n) { // Note: The Solution object is instantiated only once and is reused by each test case. int count = 0; int now = A[0]; for(int i = 1; i \u0026lt; n-count; i++) { if(now == A[i]) { for(int j = i+1; j \u0026lt; n-count; j++) { int tmp = A[j]; A[j] = A[j-1]; A[j-1] = tmp; } count++; i--; } else { now = A[i]; } } return n - count; } }; ","date":"2015-05-19T04:43:07Z","permalink":"https://blog.coinidea.com/en/p/leetcode_26-remove-duplicates-from-sorted-array/","title":"[leetcode_26] Remove Duplicates from Sorted Array"},{"content":"This problem was tricky! You really need to understand English well and read the problem carefully.\nAt first I thought I just needed to return the length after deletion. But that\u0026rsquo;s not all \u0026ndash; you also need to make sure the first length elements of array A are valid.\nGot WA at first, then Accepted on the next try.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public: int removeElement(int A[], int n, int elem) { // Note: The Solution object is instantiated only once and is reused by each test case. int length = 0; int *B = new int[n]; for(int i = 0;i \u0026lt; n;i++) { if(A[i] != elem) { B[length++] = A[i]; } } for(int i = 0;i \u0026lt; length;i++) { A[i] = B[i]; } return length; } }; A better approach would be to use two pointers and swap elements with the end of the array.\n","date":"2015-05-18T01:57:48Z","permalink":"https://blog.coinidea.com/en/p/leetcode_27remove-element/","title":"[leetcode_27]Remove Element"},{"content":"Climbing stairs: you can either climb one step or two steps at a time. How many different ways can you climb to the top?\nUsing a search approach would result in TLE. So I switched to an iterative approach:\na[n] = a[n-1] + a[n-2]\nAccepted on the first try.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public: int climbStairs(int n) { // Note: The Solution object is instantiated only once and is reused by each test case. int a1 = 1; int a2 = 2; if(n == 1) { return a1; } if(n == 2) { return a2; } int index = 3; int before = a2; int now = a1 + a2; while(true) { if(index == n) { return now; } int tmp = before; before = now; now = tmp + before; index++; } } }; ","date":"2015-05-18T01:55:36Z","permalink":"https://blog.coinidea.com/en/p/leetcode_70climbing-stairs/","title":"[leetcode_70]Climbing Stairs"},{"content":"Remove duplicate values from a sorted linked list. For linked list problems, I\u0026rsquo;ve found that keeping track of before, now, and next pointers makes the logic much simpler.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public: ListNode *deleteDuplicates(ListNode *head) { // Note: The Solution object is instantiated only once and is reused by each test case. ListNode *headbackup = head; int val = 0; if(head == NULL) { return headbackup; } ListNode * before = head; ListNode * now = head-\u0026gt;next; val = before-\u0026gt;val; while(now != NULL) { if(val != now-\u0026gt;val) { val = now-\u0026gt;val; before = now; now = now-\u0026gt;next; } else { now = now-\u0026gt;next; before-\u0026gt;next = now; } } return headbackup; } }; ","date":"2015-05-18T01:41:36Z","permalink":"https://blog.coinidea.com/en/p/leetcode_83remove-duplicates-from-sorted-list/","title":"[leetcode_83]Remove Duplicates from Sorted List"},{"content":"Simple problem, use binary search. If the target is found, return its index; if not, return the index where it should be inserted.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public: int ans; int searchInsert(int A[], int n, int target) { // Note: The Solution object is instantiated only once and is reused by each test case. ans = 0; bsearch(0,n-1,A,target); return ans; } void bsearch(int left,int right,int A[],int target) { if(left \u0026amp;amp;gt; right) { ans = left; return ; } int mid = (left + right) / 2; if(A[mid] == target) { ans = mid; return ; } else if(A[mid] \u0026amp;amp;gt; target) { bsearch(left,mid-1,A,target); } else { bsearch(mid+1,right,A,target); } } }; ","date":"2015-05-18T01:37:10Z","permalink":"https://blog.coinidea.com/en/p/leetcode_35search-insert-position/","title":"[leetcode_35]Search Insert Position"},{"content":"Check whether two trees are exactly the same. Accepted on the first try by simply enumerating all cases.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public: bool ans; bool isSameTree(TreeNode *p, TreeNode *q) { // Note: The Solution object is instantiated only once and is reused by each test case. ans = true; check(p,q); return ans; } void check(TreeNode *p,TreeNode *q) { if((p == NULL \u0026amp;\u0026amp; q != NULL) || (p != NULL \u0026amp;\u0026amp; q == NULL)) { ans = false; return; } else if(p == NULL \u0026amp;\u0026amp; q == NULL) { return ; } else { if(p-\u0026gt;val != q-\u0026gt;val) { ans = false; return; } else { check(p-\u0026gt;left,q-\u0026gt;left); check(p-\u0026gt;right,q-\u0026gt;right); } } } }; ","date":"2015-05-18T01:31:33Z","permalink":"https://blog.coinidea.com/en/p/leetcode_100same-tree/","title":"[leetcode_100]Same Tree"},{"content":"The problem is straightforward: given a binary tree, find its depth.\nGot a Runtime Error once and a Compile Error once (due to redefinition in submitted code). Finally got Accepted.\nFor the RE, note that if root is NULL, you need to return 0 immediately. Otherwise, just use DFS.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public: int depth; int maxDepth(TreeNode *root) { // Note: The Solution object is instantiated only once and is reused by each test case. if(root == NULL) return 0; depth = 1; query(root,1); return depth; } void query(TreeNode *node,int k) { if(node-\u0026gt;left == NULL \u0026amp;\u0026amp; node-\u0026gt;right == NULL) { if(k \u0026gt; depth) depth = k; } if(node-\u0026gt;left != NULL) { query(node-\u0026gt;left,k+1); } if(node-\u0026gt;right != NULL) { query(node-\u0026gt;right,k+1); } } }; ","date":"2015-05-17T02:06:07Z","permalink":"https://blog.coinidea.com/en/p/leetcode_104maximum-depth-of-binary-tree/","title":"[leetcode_104]Maximum Depth of Binary Tree"},{"content":"Given an array where every element appears twice except for one, find that single element without using extra memory.\nThis problem can be solved using XOR, which requires no extra memory.\nAccepted on the first try. Here is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public: int singleNumber(int A[], int n) { // Note: The Solution object is instantiated only once and is reused by each test case. int ans = A[0]; for(int i = 1; i \u0026lt; n; i++) { ans = ans ^ A[i]; } return ans; } }; ","date":"2015-05-17T02:04:07Z","permalink":"https://blog.coinidea.com/en/p/leetcode_136single-number/","title":"[leetcode_136]Single Number"},{"content":"This is the reverse of the previous problem.\nHehe, my first sneaky thought was to use the previous problem\u0026rsquo;s code to build a lookup table for all numbers up to 3999, but I felt that would be too cheap.\nSo I decided to solve it properly.\nOf course, the previous solution had way too many switch statements and if-else blocks.\nSo I decided to improve the approach.\nHere\u0026rsquo;s the code \u0026ndash; AC on the first try again:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Solution { public: int num; int romanToInt(string s) { // Note: The Solution object is instantiated only once and is reused by each test case. num = 0; string sub[] = { \u0026#34;CM\u0026#34;,\u0026#34;DCCC\u0026#34;,\u0026#34;DCC\u0026#34;,\u0026#34;DC\u0026#34;,\u0026#34;D\u0026#34;,\u0026#34;CD\u0026#34;,\u0026#34;CCC\u0026#34;,\u0026#34;CC\u0026#34;,\u0026#34;C\u0026#34;, \u0026#34;XC\u0026#34;,\u0026#34;LXXX\u0026#34;,\u0026#34;LXX\u0026#34;,\u0026#34;LX\u0026#34;,\u0026#34;L\u0026#34;,\u0026#34;XL\u0026#34;,\u0026#34;XXX\u0026#34;,\u0026#34;XX\u0026#34;,\u0026#34;X\u0026#34;, \u0026#34;IX\u0026#34;,\u0026#34;VIII\u0026#34;,\u0026#34;VII\u0026#34;,\u0026#34;VI\u0026#34;,\u0026#34;V\u0026#34;,\u0026#34;IV\u0026#34;,\u0026#34;III\u0026#34;,\u0026#34;II\u0026#34;,\u0026#34;I\u0026#34; }; int q[] = { 900,800,700,600,500,400,300,200,100, 90,80,70,60,50,40,30,20,10, 9,8,7,6,5,4,3,2,1 }; int i; for(i = 0;i \u0026lt; s.size();i++) { if(s[i] != \u0026#39;M\u0026#39;) break; else num += 1000; } s = s.substr(i,s.size()); for(int i = 0;i \u0026lt; 27;i++) { s = stringtoint(s,i,sub,q); } return num; } string stringtoint(string s,int i,string sub[],int q[]) { if(finds(s,sub[i])) { num += q[i]; s = s.substr(sub[i].length(),s.size()-1); } return s; } bool finds(string s,string sub) { if(s.size() \u0026lt; sub.size()) return false; for(int i = 0;i \u0026lt; sub.size();i++) { if(s[i] != sub[i]) return false; } return true; } }; ","date":"2015-05-17T02:01:11Z","permalink":"https://blog.coinidea.com/en/p/leetcode-13-roman-to-integer/","title":"[LeetCode 13] Roman to Integer"},{"content":"This problem asks you to convert a number (1-3999) to Roman numerals. Not exactly easy, not exactly hard.\nReference from Baidu Baike: http://baike.baidu.com/link?url=TR8d0KXBBMWZffIDqBd_IFPSi0RZkB06DpUlsaZs-9_gCLNQaIVd2VmMwyf-3zG8\nCode:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 class Solution { public: string intToRoman(int num) { // Note: The Solution object is instantiated only once and is reused by each test case. char schar[10]; int index = 0; int count; if(num / 1000 != 0) { count = num / 1000; num = num % 1000; for(int i = 0; i \u0026lt; count; i++) { schar[index++] = \u0026#39;M\u0026#39;; } } if(num / 100 != 0) { count = num / 100; num = num % 100; switch(count) { case 1: schar[index++] = \u0026#39;C\u0026#39;; break; case 2: schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; break; case 3: schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; break; case 4: schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;D\u0026#39;; break; case 5: schar[index++] = \u0026#39;D\u0026#39;; break; case 6: schar[index++] = \u0026#39;D\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; break; case 7: schar[index++] = \u0026#39;D\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; break; case 8: schar[index++] = \u0026#39;D\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; break; case 9: schar[index++] = \u0026#39;C\u0026#39;; schar[index++] = \u0026#39;M\u0026#39;; break; } } if(num / 10 != 0) { count = num / 10; num = num % 10; switch(count) { case 1: schar[index++] = \u0026#39;X\u0026#39;; break; case 2: schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; break; case 3: schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; break; case 4: schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;L\u0026#39;; break; case 5: schar[index++] = \u0026#39;L\u0026#39;; break; case 6: schar[index++] = \u0026#39;L\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; break; case 7: schar[index++] = \u0026#39;L\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; break; case 8: schar[index++] = \u0026#39;L\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; break; case 9: schar[index++] = \u0026#39;X\u0026#39;; schar[index++] = \u0026#39;C\u0026#39;; break; } } if(num != 0) { count = num; switch(count) { case 1: schar[index++] = \u0026#39;I\u0026#39;; break; case 2: schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; break; case 3: schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; break; case 4: schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;V\u0026#39;; break; case 5: schar[index++] = \u0026#39;V\u0026#39;; break; case 6: schar[index++] = \u0026#39;V\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; break; case 7: schar[index++] = \u0026#39;V\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; break; case 8: schar[index++] = \u0026#39;V\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;I\u0026#39;; break; case 9: schar[index++] = \u0026#39;I\u0026#39;; schar[index++] = \u0026#39;X\u0026#39;; break; default: break; } } schar[index] = \u0026#39;\\0\u0026#39;; string s = schar; return s; } }; ","date":"2015-05-17T01:58:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode-12-integer-to-roman/","title":"[LeetCode 12] Integer to Roman"},{"content":"OK, I couldn\u0026rsquo;t figure this one out on my own. After struggling on and off, I eventually gave in and looked at other people\u0026rsquo;s approaches.\nLet me share my thought process.\nThe first idea was brute force: pick every pair of lines, calculate the volume, and find the maximum.\nThe logic is correct, but it timed out. I checked the test cases \u0026ndash; the data set is quite large.\nSo what next? We clearly need an approach with complexity lower than $O(n^2)$ to pass.\nI thought for a long time. Sorting? Filling water from bottom up? Two pointers, one on each side, moving inward? Or fix the left side and assume the other line is always to the right?\nIt was all over the place.\nFinally I looked at someone else\u0026rsquo;s solution, and it\u0026rsquo;s really so easy \u0026ndash; I can\u0026rsquo;t believe I didn\u0026rsquo;t think of it. Sigh.\nThe approach is simple: greedy.\nTwo pointers, one on each end. Record the volume. Move the pointer at the shorter line inward. People online call this the \u0026ldquo;two-pointer\u0026rdquo; technique.\nDuring implementation, when the two lines are equal in height, you could move either the left or the right pointer. So the best approach is to use recursion to handle both cases.\nHere\u0026rsquo;s the code. Solving problems can be quite painful, especially for someone slow like me. Keep going!\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public: int sum; int maxArea(vector\u0026lt;int\u0026gt; \u0026amp;height) { // Note: The Solution object is instantiated only once and is reused by each test case. sum = 0; int left = 0; int right = height.size() - 1; func(left, right, height); return sum; } void func(int left, int right, vector\u0026lt;int\u0026gt; \u0026amp;height) { if (left \u0026lt; right) { int min = height[left]; if (min \u0026gt; height[right]) min = height[right]; int tmp = min * (right-left); if (tmp \u0026gt; sum) sum = tmp; if (height[left] \u0026gt; height[right]) { func(left, right-1, height); } else if (height[left] \u0026lt; height[right]) { func(left+1, right, height); } else { func(left+1, right, height); func(left, right-1, height); } } } }; ","date":"2015-05-17T01:51:40Z","permalink":"https://blog.coinidea.com/en/p/leetcode-11-container-with-most-water/","title":"[LeetCode 11] Container With Most Water"},{"content":"This problem is simple: determine whether an int is a palindrome.\nNote that negative numbers are not palindromes. Just convert the int to a character array and check directly.\nAccepted on the first try.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { public: bool isPalindrome(int x) { // Note: The Solution object is instantiated only once and is reused by each test case. if(x \u0026lt; 0) return false; char s[100]; int index = 0; while(x \u0026gt; 0) { s[index++] = x%10; x /= 10; } int i = 0; int j = index-1; while(i \u0026lt;= j) { if(s[i] != s[j]) return false; i++; j--; } return true; } }; ","date":"2015-05-17T01:48:59Z","permalink":"https://blog.coinidea.com/en/p/leetcode_9palindrome-number/","title":"[leetcode_9]Palindrome Number"},{"content":"This problem really taught me the importance of reading the problem statement carefully. I kept getting WA after WA\u0026hellip;\nThe problem is simple: read a string, convert it to an int, and if it overflows, output the boundary value.\nHowever, you need to handle the + and - signs. Also worth noting: first skip all leading spaces, then start parsing from the first non-space character, and continue until you encounter an unrecognizable character.\nA special case: for a string like \u0026rsquo; a123123123\u0026rsquo;, you need to return 0.\nThe algorithm and data structure are not difficult. Here is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class Solution { public: int atoi(const char *str) { // Note: The Solution object is instantiated only once and is reused by each test case. int i; for (i = 0; i \u0026lt; strlen(str); i++) { if (str[i] != \u0026#39; \u0026#39;) break; } if (!((str[i] \u0026gt;= \u0026#39;0\u0026#39; \u0026amp;\u0026amp; str[i] \u0026lt;= \u0026#39;9\u0026#39;) || (str[i] == \u0026#39;+\u0026#39;) || (str[i] == \u0026#39;-\u0026#39;))) return 0; int start = -1; int end = -1; for (; i \u0026lt; strlen(str); i++) { if ((str[i] \u0026gt;= \u0026#39;0\u0026#39; \u0026amp;\u0026amp; str[i] \u0026lt;= \u0026#39;9\u0026#39;) || (str[i] == \u0026#39;+\u0026#39;) || (str[i] == \u0026#39;-\u0026#39;)) { start = i; break; } } if (start == -1) return 0; for (i = start + 1; i \u0026lt; strlen(str); i++) { if (str[i] \u0026lt; \u0026#39;0\u0026#39; || str[i] \u0026gt; \u0026#39;9\u0026#39;) { end = i - 1; break; } } if (i == strlen(str)) { end = i - 1; } int p = 1; if (str[start] == \u0026#39;-\u0026#39; || str[start] == \u0026#39;+\u0026#39;) { if (str[start] == \u0026#39;-\u0026#39;) p = -1; start++; } double ans = 0; int index = 0; for (i = end; i \u0026gt;= start; i--) { ans += (str[i] - \u0026#39;0\u0026#39;) * pow(10.0, index++); } ans = ans * p; if (ans \u0026gt; 2147483647.0) return 2147483647; if (ans \u0026lt; -2147483648.0) return -2147483648; return (int)ans; } }; ","date":"2015-05-17T01:46:23Z","permalink":"https://blog.coinidea.com/en/p/leetcode_8-string-to-integer-atoi/","title":"[leetcode_8] String to Integer (atoi)"},{"content":"I just complained about unclear problem statements, and then this problem gives a whole bunch of clarifications and notes:\nHave you thought about this?\nHere are some good questions to ask before coding. Bonus points for you if you have already thought through this!\nIf the integer’s last digit is 0, what should the output be? ie, cases such as 10, 100.\nDid you notice that the reversed integer might overflow? Assume the input is a 32-bit integer, then the reverse of 1000000003 overflows. How should you handle such cases?\nThrow an exception? Good, but what if throwing an exception is not an option? You would then have to re-design the function (ie, add an extra parameter).\nOther than the overflow issue which I didn\u0026rsquo;t consider, the rest of the points are worth noting.\nAccepted on the first try.\nStore the digits in an array and add them back in reverse order, so the trailing zeros issue is naturally resolved.\nHere is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public: int reverse(int x) { // Note: The Solution object is instantiated only once and is reused by each test case. int num[100]; int top = 0; while(true) { num[top++] = x%10; x /= 10; if(x == 0) break; } int ans = 0; for(int i = 0;i \u0026lt; top;i++) { ans += num[i]*(int)pow(10.0,top - i - 1); } return ans; } }; ","date":"2015-05-17T01:44:49Z","permalink":"https://blog.coinidea.com/en/p/leetcode_7reverse-integer/","title":"[leetcode_7]Reverse Integer"},{"content":"This problem was really frustrating!!! The problem statement is deceptively simple!\nThe string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)\nP A H N\nA P L S I I G\nY I R\nAnd then read line by line: “PAHNAPLSIIGYIR”\nWrite the code that will take a string and make this conversion given a number of rows:\nstring convert(string text, int nRows);\nconvert(“PAYPALISHIRING”, 3) should return “PAHNAPLSIIGYIR”.\nThe problem didn\u0026rsquo;t explain itself clearly. At first I thought the format was:\nX X X X\nX X X X X X\n…\nwhere the first row has one letter with three spaces in between, and the second row has one letter with one space in between.\nFollowing this logic, I assumed odd rows had X letters and even rows had 2X-1 letters. I wrote the code based on this idea and submitted it confidently:\n142 / 1158 test cases passed.\nPassed 142 test cases\u0026hellip; then it said ABCD 2 was WA?\nI was completely confused. Finally, with no other options, I looked up how others interpreted the problem.\nTurns out it means:\n1 7\n2 6 8\n3 5 9\n4\nIt should form a zigzag pattern\u0026hellip; then output row by row\u0026hellip; sigh.\nSo I started working on it, using a 2D array to store the values, changing direction, and filling empty spots with spaces\u0026hellip; Got all kinds of RE on small test cases??? That didn\u0026rsquo;t make sense. Then I realized it might be RE on large data but just happened to be running on small data first.\nEventually I tried expanding the 2D array to 10000x10000 and it blew up with memory issues.\nWhat to do? I almost gave up on this problem.\nIt all came down to my own inexperience. Later I thought of two approaches: either use a mathematical method to calculate the output order, or compress the space. I chose the latter \u0026ndash; instead of storing a 2D map array, I stored each letter\u0026rsquo;s x, y coordinates and value, which greatly reduced the space usage.\nAccepted on the first try after that!\nNotes:\nNeed to handle the special case of a single row. I was lazy and used the standard library\u0026rsquo;s sort. Here is the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include \u0026lt;algorithm\u0026gt; using namespace std; struct Node { int x; int y; char val; }p[10000]; int cmp(Node a,Node b) { if(a.x == b.x) { return a.y \u0026lt; b.y; } else { return a.x \u0026lt; b.x; } } class Solution { public: string convert(string s, int nRows) { // Note: The Solution object is instantiated only once and is reused by each test case. int x = 0; int y = 0; int direction = 0; if(nRows == 1) return s; for(int i = 0; i \u0026lt; s.length(); i++) { p[i].x = x; p[i].y = y; p[i].val = s[i]; if(direction == 0) { x++; if(x \u0026gt;= nRows) { x--; direction = 1; x--; y++; } } else { x--; y++; if(x \u0026lt; 0) { x++; y--; direction = 0; x++; } } } sort(p, p + s.length(), cmp); for(int i = 0; i \u0026lt; s.length(); i++) { s[i] = p[i].val; } return s; } }; ","date":"2015-05-17T01:39:59Z","permalink":"https://blog.coinidea.com/en/p/leetcode_6zigzag-conversion/","title":"[leetcode_6]ZigZag Conversion"},{"content":"Wow, this one is a beast \u0026ndash; also took me an entire afternoon.\nThe problem is: given a string, find the longest palindromic substring.\nThe first approach I thought of was brute force \u0026ndash; just get it working first.\nHow to brute force? My initial idea was: Use a fixed function check to determine if a string is a palindrome. If s is a palindrome, we\u0026rsquo;re done. Otherwise, check s(0, s.length()-2) and s(1, s.length()-1).\nI wrote this code and tested it \u0026ndash; works fine for short strings. But thinking about it, the complexity is way too high, especially for slightly longer strings.\nSure enough, it timed out.\nTLE means the approach is wrong \u0026ndash; time to rethink.\nLet\u0026rsquo;s try the reverse approach: First check if s[i] is a palindrome, then expand by 1 on each side. Then check if s[i], s[i+1] is a palindrome, then expand by 1 on each side. The two cases are needed because of the odd/even length distinction.\nOK, this should optimize the time for most cases.\nBut still TLE. However, we\u0026rsquo;re getting closer to the solution.\nHere\u0026rsquo;s the next insight: we don\u0026rsquo;t actually need to expand by 1 each time. If we\u0026rsquo;ve already found a palindrome of length sum, when we enumerate the next center point, we can start expanding from sum/2. And that got AC!\nThe few WAs were just boundary issues.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Solution { public: int sum; int step; string ans; string longestPalindrome(string s) { // Note: The Solution object is instantiated only once and is reused by each test case. sum = 0; for(int i = 0;i \u0026lt; s.length();i++) { step = sum/2; if(i-step \u0026lt; 0 || i+step \u0026gt;= s.length()) continue; func(s,i-step,i+step); } for(int i = 0;i \u0026lt; s.length();i++) { step = sum/2; if(i-step \u0026lt; 0 || i+step+1 \u0026gt;= s.length()) continue; func(s,i-step,i+1+step); } return ans; } void func(string s,int x,int y) { if(x \u0026lt; 0 || y \u0026gt; s.length()-1)return; if(checkp(s.substr(x,y-x+1))) { if(sum \u0026lt; y-x+1) { sum = y-x+1; ans = s.substr(x,y-x+1); } func(s,x-1,y+1); } } bool checkp(string s) { int i = 0; int j = s.length() - 1; while(i \u0026lt;= j) { if(s[i] != s[j]) return false; i++; j--; } return true; } }; ","date":"2015-05-15T02:19:37Z","permalink":"https://blog.coinidea.com/en/p/leetcode-5-longest-palindromic-substring/","title":"[LeetCode 5] Longest Palindromic Substring"},{"content":"Man, this problem looks simple from the name, but it nearly killed me. The idea is clear, but the implementation was painful. My fundamentals really need work \u0026ndash; it took forever.\nThe problem says: given two non-negative linked lists, add the corresponding values of the two lists. If the sum is 10 or greater, there\u0026rsquo;s a carry \u0026ndash; and the carry is what really tripped me up. Got WA once because of it.\nOne thing to note is that the numbers need to be reversed. I directly reversed both input linked lists, which led to AC. If you miss this, you\u0026rsquo;ll likely get wrong answers. But reversing a linked list really frustrated me \u0026ndash; I need to practice my fundamentals more.\nThere\u0026rsquo;s also the issue of deep copy vs. shallow copy with pointers.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { public: double findMedianSortedArrays(int A[], int m, int B[], int n) { // Note: The Solution object is instantiated only once and is reused by each test case. int sum = m + n; if (sum % 2 == 0) { return (findk(A, m, B, n, sum/2) + findk(A, m, B, n, sum/2 + 1)) / 2; } else { return findk(A, m, B, n, sum/2 + 1); } } double findk(int A[], int m, int B[], int n, int k) { if (m \u0026gt; n) { return findk(B, n, A, m, k); } if (m \u0026lt;= 0) return B[k-1]; if (n \u0026lt;= 0) return A[k-1]; if (k == 1) { if (A[0] \u0026lt; B[0]) return A[0]; else return B[0]; } int a = k/2; if (m \u0026lt; k/2) a = m; int b = k - a; if (A[a-1] == B[b-1]) return A[a-1]; else if (A[a-1] \u0026lt; B[b-1]) { return findk(A + a, m - a, B, n, k - a); } else { return findk(A, m, B + b, n - b, k - b); } } }; ","date":"2015-05-15T02:16:42Z","permalink":"https://blog.coinidea.com/en/p/leetcode-2-add-two-numbers/","title":"[LeetCode 2] Add Two Numbers"},{"content":"I initially thought this problem would require fancy algorithms, but I ended up using what I consider the simplest approach.\nLet me explain my thought process.\nAt first, I was a bit confused and naively thought: start enumerating from the first element of the array, and if a later element is different from the \u0026ldquo;first\u0026rdquo; element, stop and move to the next loop, then output the maximum sum.\nObviously that\u0026rsquo;s wrong! It should be: a later element must be different from ALL previous elements.\nWA #1.\nOK, this brute force approach did pass. Now, the problem says \u0026ldquo;characters\u0026rdquo; \u0026ndash; if we\u0026rsquo;re talking about English letters including both upper and lower case, that\u0026rsquo;s 26*2. All ASCII characters would be 256. I allocated an array of 300, which should be enough.\nThe logic was correct but I still got WA #2. Why? Because the termination condition wasn\u0026rsquo;t explicit enough. If there are no repeating characters all the way to the end, my program would break.\nWA #3 was because the program would crash when there\u0026rsquo;s only one element. Boundary conditions matter a lot for simple problems!\nFinally it was pending for a while \u0026ndash; I kept thinking it would time out, but it didn\u0026rsquo;t.\nYay!\nActually, the time complexity can be further optimized. If we start searching from position x, and elements at positions i and j are the same, the next search can start from i+1 instead of x+1. This would keep the time at linear scanning, though we\u0026rsquo;d need to store the indices of i and j.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public: int lengthOfLongestSubstring(string s) { // Note: The Solution object is instantiated only once and is reused by each test case. int sum = 0; if(s.length() == 1) return 1; for(int i = 0; i \u0026lt; s.length(); i++) { int flag[300]; for(int k = 0; k \u0026lt; 300; k++) { flag[k] = 0; } flag[s[i]] = 1; for(int j = i+1; j \u0026lt; s.length(); j++) { if(flag[s[j]] == 1) { if(j - i \u0026gt; sum) sum = j - i; break; } if(j == s.length() - 1) { if(j - i + 1 \u0026gt; sum) sum = j - i + 1; break; } flag[s[j]] = 1; } } return sum; } }; ","date":"2015-05-15T02:12:51Z","permalink":"https://blog.coinidea.com/en/p/leetcode-3-longest-substring-without-repeating-characters/","title":"[LeetCode 3] Longest Substring Without Repeating Characters"},{"content":"Honestly, I couldn\u0026rsquo;t solve this one on my first attempt. I only figured it out after reading someone else\u0026rsquo;s approach, and I still made boundary errors multiple times. Embarrassing.\nLet me explain the approach.\nMy initial idea was: merge sort the two arrays, then output array[median]. But clearly this has a time complexity higher than $O(\\log(m+n))$ \u0026ndash; it\u0026rsquo;s about $O(m+n)$.\nThe time complexity constraint is what makes this problem frustrating.\nOK, looking at the conditions again: two already sorted arrays, and the required time complexity is logarithmic. What does that remind you of? Binary search?\nBut how do you apply binary search to this problem? There\u0026rsquo;s a bit of math involved.\nFor the detailed derivation, see: http://blog.chinaunix.net/uid-28490468-id-3576490.html\nI had seen another blog post about this before, but I can\u0026rsquo;t find it anymore. Oh well.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 ListNode *l; class Solution { public: ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { // Note: The Solution object is instantiated only once and is reused by each test case. l1 = Reverse(l1); l2 = Reverse(l2); ListNode *ans = NULL; ListNode *ansbackup = NULL; int sum = 0; int now = 0; int next = 0; while(true) { if(l1 == NULL || l2 == NULL) break; sum = l1-\u0026gt;val + l2-\u0026gt;val+next; now = sum % 10; next = sum / 10; ListNode *tmp = new ListNode(now); if(ans == NULL) { ans = tmp; ansbackup = ans; } else { ans-\u0026gt;next = tmp; ans = ans-\u0026gt;next; } l1 = l1-\u0026gt;next; l2 = l2-\u0026gt;next; } if(l1 != NULL) { while(true) { if(l1 == NULL) break; sum = l1-\u0026gt;val + next; now = sum % 10; next = sum / 10; ListNode *tmp = new ListNode(now); ans-\u0026gt;next = tmp; ans = ans-\u0026gt;next; l1 = l1-\u0026gt;next; } } if(l2 != NULL) { while(true) { if(l2 == NULL) break; sum = l2-\u0026gt;val + next; now = sum % 10; next = sum / 10; ListNode *tmp = new ListNode(now); ans-\u0026gt;next = tmp; ans = ans-\u0026gt;next; l2 = l2-\u0026gt;next; } } if(next != 0) { ListNode *tmp = new ListNode(next); ans-\u0026gt;next = tmp; ans = ans-\u0026gt;next; } return ansbackup; } ListNode *Reverse(ListNode *l) { ListNode *before; ListNode *now; ListNode *next; if(l-\u0026gt;next == NULL) return l; before = l; now = l-\u0026gt;next; while(now == NULL) { next = now-\u0026gt;next; now-\u0026gt;next = before; before = now; now = next; } return before; } }; ","date":"2015-05-15T02:08:02Z","permalink":"https://blog.coinidea.com/en/p/leetcode-4-median-of-two-sorted-arrays/","title":"[LeetCode 4] Median of Two Sorted Arrays"},{"content":"The problem asks: given an array numbers and a target, find two indices index1 and index2 such that the two numbers at those indices sum to target.\nNote that the indices in numbers start from 1, but vector as a built-in array actually has 0-based indexing.\nSince I just started doing LeetCode problems, I\u0026rsquo;m still getting used to it \u0026ndash; it\u0026rsquo;s quite different from the online judges I used before.\nIn particular, I had never worked with vector before, and now I truly realize how much of a C++ beginner I am.\nHere\u0026rsquo;s a blog post for learning about vectors: http://www.cnblogs.com/charley_yang/archive/2010/12/11/1903040.html\nJust treat vector as an array.\nHere\u0026rsquo;s my solution and approach:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public: vector\u0026lt;int\u0026gt; twoSum(vector\u0026lt;int\u0026gt; \u0026amp;numbers, int target) { // Note: The Solution object is instantiated only once and is reused by each test case. vector\u0026lt;int\u0026gt; answer(2); for(int i = 0; i \u0026lt; numbers.size(); i++) { int flag = false; for(int j = 0; j \u0026lt; numbers.size(); j++) { if(i != j \u0026amp;\u0026amp; numbers[i] + numbers[j] == target) { answer[0] = i + 1; answer[1] = j + 1; flag = true; break; } } if(flag == true) break; } return answer; } }; The approach is straightforward \u0026ndash; brute force.\nGot AC on the first try, though the runtime was 32ms. This method is $O(n^2)$ \u0026ndash; can we do better?\nI thought about it: if we sort the vector first in $O(n \\log n)$, then for each number, compute the difference with target and binary search for it, the overall complexity would be $O(n \\log n)$. That should be faster \u0026ndash; though we\u0026rsquo;d need to handle index preservation.\n","date":"2015-05-15T01:28:40Z","permalink":"https://blog.coinidea.com/en/p/leetcode-1-two-sum/","title":"[LeetCode 1] Two Sum"},{"content":"I recently had a requirement to count the number of valid (non-empty) lines in a textarea on a page, limit the total number of lines, and display the remaining available lines. [Besides counting lines, you could also check for spaces, commas, semicolons, etc. \u0026ndash; the approach is similar.]\nMy initial idea was: Write a regex to replace multiple consecutive newlines \u0026ldquo;\\n\u0026rdquo; with a single \u0026ldquo;\\n\u0026rdquo;: str.replace(/\\n+/, \u0026quot;\\n\u0026quot;); But this doesn\u0026rsquo;t handle cases where there are multiple empty lines with leading spaces.\nLater: Simply split by \u0026ldquo;\\n\u0026rdquo;, then count entries with length greater than 0 as valid lines.\nHere\u0026rsquo;s the code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 \u0026lt;script type=\u0026#34;text/javascript\u0026#34;\u0026gt; var maxTagCount = 100; function checkLine(textArea) { var str = textArea.value; var lines = str.split(\u0026#39;\\n\u0026#39;); var countLine = 0; for (var i = 0; i \u0026lt; lines.length; i++) { if (lines[i].length \u0026gt; 0) { countLine++; } } var tagElement = document.getElementById(\u0026#34;tagTextarea\u0026#34;); if (countLine \u0026gt; maxTagCount) { var varNewValue = \u0026#34;\u0026#34;; var index = 0; for (var i = 0; i \u0026lt; lines.length; i++) { if (index \u0026gt;= maxTagCount) { break; } if (lines[i].length \u0026gt; 0) { index++; } varNewValue += lines[i]; varNewValue += \u0026#34;\\n\u0026#34;; } textArea.value = varNewValue; stat_left.innerHTML = 0; } else { stat_left.innerHTML = maxTagCount - countLine; } } \u0026lt;/script\u0026gt; Web demo: countLines ","date":"2015-03-19T12:30:42Z","permalink":"https://blog.coinidea.com/en/p/counting-valid-lines-in-a-textarea-with-javascript/","title":"Counting Valid Lines in a Textarea with JavaScript"},{"content":"The front-end of my previous websites was built entirely with Bootstrap.\nI usually use Chrome, but one day I checked my website on IE6 running on XP, and it was a disaster. I had completely forgotten about browser compatibility. So I tested on:\nChrome, Opera, Firefox, IE 5.5-10 [using IE Tester]\nThe main issues were with IE, so I started looking for solutions:\nhttp://www.jqueryba.com/1194.html\nAdd:\n1 2 3 \u0026lt;!--[if IE]\u0026gt; \u0026lt;script src=\u0026#34;http://html5shiv.googlecode.com/svn/trunk/html5.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;![endif]--\u0026gt; Or directly add:\n1 2 3 4 5 \u0026lt;!--[if IE]\u0026gt; \u0026lt;script\u0026gt; (function(){if(!/*@cc_on!@*/0)return;var e = \u0026#34;abbr,article,aside,audio,canvas,datalist,details,dialog,eventsource,figure,footer,header,hgroup,mark,menu,meter,nav,output,progress,section,time,video\u0026#34;.split(\u0026#39;,\u0026#39;),i=e.length;while(i--){document.createElement(e[i])}})() \u0026lt;/script\u0026gt; \u0026lt;![endif]--\u0026gt; Then:\n1 header, footer, article, section, nav, menu, hgroup {display: block;} 1 2 3 4 5 6 7 8 9 \u0026lt;script type=\u0026#34;text/javascript\u0026#34;\u0026gt; document.createElement(\u0026#34;section\u0026#34;); document.createElement(\u0026#34;article\u0026#34;); document.createElement(\u0026#34;footer\u0026#34;); document.createElement(\u0026#34;header\u0026#34;); document.createElement(\u0026#34;hgroup\u0026#34;); document.createElement(\u0026#34;nav\u0026#34;); document.createElement(\u0026#34;menu\u0026#34;); \u0026lt;/script\u0026gt; The results weren\u0026rsquo;t great though \u0026ndash; many nav elements and alignments were off.\nBSIE [Bootstrap IE] http://www.bootcss.com/p/bsie/ This is an open-source library built on top of Bootstrap. The demo looked great, but due to legacy reasons, my site was already built and making changes was too difficult, so I had to give up.\nThe final solution: just embed two JS files.\nhtml5shiv.js + respond.js Yes, just these two JS files. At least IE7 and above now display properly. There are still some minor issues like rounded corners, but the nav, grid layout, and overall appearance work well. Very satisfying.\n","date":"2015-03-07T07:24:29Z","permalink":"https://blog.coinidea.com/en/p/making-bootstrap-compatible-with-ie/","title":"Making Bootstrap Compatible with IE"},{"content":"CoinVote is a flexible voting system. CoinVote was independently developed by me in 2015 and features the following:\nVoting homepage View votes Vote listings Candidate listings Edit candidates Demo | Details\n","date":"2015-02-19T06:05:31Z","permalink":"https://blog.coinidea.com/en/p/coinvote--a-voting-system/","title":"CoinVote -- A Voting System"},{"content":"CoinCMS is a clean and simple portal system. CoinCMS was independently developed by me in 2015 and features the following:\nPortal homepage Category listings Article publishing Admin panel Demo | Details\n","date":"2015-02-19T05:54:17Z","permalink":"https://blog.coinidea.com/en/p/coincms--a-portal-system/","title":"CoinCMS -- A Portal System"},{"content":"While organizing old files recently, I stumbled upon a small program I wrote around 2011.\nHave you ever played a game called Bookworm? It\u0026rsquo;s made by PopCap. The game tells the story of a bookworm defeating a demon, and to progress and fight bosses, you need to spell words. If I recall correctly, you\u0026rsquo;re given a 3x3 or 4x4 matrix containing letters a-z or * (representing any letter), and you need to spell the longest word possible \u0026ndash; the longer the word, the more damage dealt to the demon. So I wrote a little program to help my not-so-great vocabulary spell the longest words possible. It requires a word list as a prerequisite; there\u0026rsquo;s a dictionary.txt in the project\u0026rsquo;s doc folder containing about 7000+ words that needs to be loaded first.\nMain program interface: Loading the dictionary: Entering characters: Getting the result list: GitHub: https://github.com/hujiulin/Bookworm\nProject notes:\nWritten in C++ around 2011 [the code is a bit messy]. Can be opened with VC 6.0 or Visual Studio. This program finds the longest possible words. Input letters [a-z or *] to get a list of answers. [* represents any letter] This was my first ever small program. I recently found it among old files, so I\u0026rsquo;m sharing it here :). ","date":"2015-02-12T15:54:15Z","permalink":"https://blog.coinidea.com/en/p/bookworm-helper-tool/","title":"Bookworm Helper Tool"},{"content":"I had been using SVN before and only truly started using Git a few months ago. I had briefly used GitHub during KDD2013.\nRecently, I wanted to polish my programs properly \u0026ndash; comments and descriptions are essential and should be written with care.\nI encountered a problem: how to add images to a README.md file.\nHere is the solution I used:\nCreate an image folder within your project folder, place the images you want to display in the README.md, and commit that folder to GitHub. Through the preview, you can obtain the image\u0026rsquo;s URL on GitHub.\nREADME.md supports the following image markup: \u0026lt;img data-original=\u0026quot;image-url\u0026quot; src=\u0026quot;http://blog.coinidea.com/wp-content/themes/9IPHP/images/lazy_loading.gif\u0026quot; alt=\u0026quot;image\u0026quot; /\u0026gt;\nExample:\nhttps://github.com/hujiulin/WordConverter\n","date":"2015-02-12T12:42:27Z","permalink":"https://blog.coinidea.com/en/p/adding-images-to-readme.md-on-github/","title":"Adding Images to README.md on GitHub"},{"content":"I went to fulfill my last wish of 2014, and it was absolutely worth it \u0026ndash; left me wanting more.\n1. Transportation I departed from Beijing, so the plan was: fly from Beijing to Shenzhen, then take the subway from Shenzhen across the border to Hong Kong.\nThe dates were January 2-5, 2015. Surprisingly, the flights were very cheap \u0026ndash; a round trip between Beijing and Shenzhen was only about 1340 RMB. I recommend Air China; it\u0026rsquo;s usually the only airline I fly.\n1.1 Accommodation Cheap flights usually depart at night, so I stayed one night in Shenzhen \u0026ndash; again at a Home Inn, which was about 130 RMB per night. From the Home Inn near Bao\u0026rsquo;an Airport to Luohu Port in Shenzhen is quite a distance, requiring a bus transfer to the subway. After that, things went smoothly. I suggest getting an individual travel permit rather than a group one \u0026ndash; it gives you more freedom. First-timers must register at the counter, but after that you can use the self-service lanes, which is very convenient.\nIn Hong Kong, I originally wanted to stay near Jordan, but hotel prices were really high since it was New Year\u0026rsquo;s. A slightly decent 3-star hotel was over 1000 RMB per night, so I chose an ibis near North Point, which was 400+ RMB cheaper than the ibis hotels closer to central Hong Kong.\nOn the last night, I stayed at the Prudential Hotel in Jordan.\nOverall, the ibis at North Point was decent \u0026ndash; it\u0026rsquo;s near the subway and very convenient. However, rooms in Hong Kong are generally small and the soundproofing isn\u0026rsquo;t great.\n1.2 Sightseeing If you want to buy Apple products, head to the big shopping mall near Hong Kong Station. There\u0026rsquo;s a 3-story Apple flagship store, and it\u0026rsquo;s always packed with buyers.\nShopping tip for Hong Kong: many salespeople will keep trying to upsell you \u0026ndash; \u0026ldquo;spend over 1000 and get X free, then add 200 more and get Y free.\u0026rdquo;\n3.1 Disneyland We bought tickets on Taobao beforehand. The seller was nice and the tickets worked. Disneyland is super fun and amazing. Unfortunately, we only spent one day there. I recommend spending two days, and definitely stay overnight at Disneyland \u0026ndash; don\u0026rsquo;t try to save money on this. There\u0026rsquo;s a direct subway line, very convenient.\n3.2 Victoria Peak and Madame Tussauds I think the cable car is worth riding \u0026ndash; it\u0026rsquo;s fairly cheap. I recommend buying the combo ticket to save money. The wax museum is small, but for a first-time visitor, I\u0026rsquo;d recommend going at least once.\n3.3 Lan Kwai Fong It\u0026rsquo;s a bar street, quite lively. But I don\u0026rsquo;t really drink, so I went there and bought my wife some Haagen-Dazs. Haha.\n3.4 The University of Hong Kong I almost ended up studying here. The campus is really impressive, though it gave me a lot to think about. The cafeteria is great \u0026ndash; delicious and cheap.\n4. Tips 4.1 Make sure to bring your ID card and travel permit. Apply for the travel permit in advance. 4.2 Consider exchanging some Hong Kong dollars beforehand, just in case. UnionPay cards are accepted almost everywhere. 4.3 Remember to bring a plug adapter, otherwise you won\u0026rsquo;t be able to charge your phone. You can buy adapters on Taobao cheaply. Here\u0026rsquo;s a photo:\nAnd a final thought:\nI work this hard just to live the life I see on TV. Keep going :)\n","date":"2015-02-11T09:28:52Z","permalink":"https://blog.coinidea.com/en/p/travel-guide-hong-kong/","title":"Travel Guide - Hong Kong"},{"content":"I set up WordPress on SAE and bound a custom domain to the application: blog.coinidea.com. The link does redirect to the blog page, but all internal links still point to app-name.sinaapp.com. This means the custom domain doesn\u0026rsquo;t apply to WordPress\u0026rsquo;s internal articles and pages.\nSolutions: Option 1: Dashboard Settings Go to the WordPress dashboard. Click \u0026ldquo;Settings\u0026rdquo;. Modify: Option 2: Direct Database Modification [More aggressive] Find the wp-options table. Modify entries #1 and #37. ","date":"2015-02-11T09:12:06Z","permalink":"https://blog.coinidea.com/en/p/wordpress-domain-configuration-on-sae/","title":"WordPress Domain Configuration on SAE"},{"content":"I went with the excitement of fulfilling the first wish of the new year.\nTransportation: I took the bullet train from Beijing to Harbin both ways. It\u0026rsquo;s quite convenient, taking about 8 hours and 10 minutes. But make sure to choose your travel time wisely. Actually, there\u0026rsquo;s one approach I\u0026rsquo;d recommend: take an overnight sleeper train departing in the evening and arriving the next day. This way you can save a night\u0026rsquo;s accommodation cost.\nThe arrival station is Harbin West Railway Station, which is quite far from the city center. However, you can take a taxi from the taxi stand at Harbin West station. I assumed taxis at the train station would be reliable, but it turned out to be slightly disappointing. I had called the hotel staff in Harbin beforehand asking how much a taxi from the station to the hotel would cost. They said about 25 RMB, or 30 at night.\nAfter I got in the taxi, I opened Baidu Maps, which also estimated about 26 RMB. I felt at ease \u0026ndash; until I noticed the driver was taking a longer route. The driver enthusiastically explained that this road had fewer traffic lights and less congestion. But it was already 11 PM. I said nothing. The fare was 38 RMB. When I pointed out the issue, the driver calmly offered a bunch of excuses that I didn\u0026rsquo;t consider valid [\u0026ldquo;I don\u0026rsquo;t care about your 1-2 extra RMB; sitting in traffic costs money too\u0026rdquo;]. I said nothing. OK, paid and got out.\nTravel tip: Book an overnight hard sleeper arriving the next day; keep your eyes open after getting in a taxi, agree on the route in advance. Xizhi Street in the city center does indeed have many traffic lights.\nAccommodation: I booked a Home Inn. I personally quite like staying at Home Inn \u0026ndash; good value for money. This time, however, there were a few issues:\nThe Gold Card comes with free breakfast, but the voucher says it must be used within 5 days. On the last day, I brought the vouchers I had saved up, only to find none of them could be used. The staff gave me no reasonable explanation \u0026ndash; just \u0026ldquo;you can\u0026rsquo;t use them, deal with it.\u0026rdquo;\nIf you can book online, pay online. I ran into an awkward issue: my room rates should have been 184, 166, 166, 166. But the staff charged me 184 every day. Fortunately, I caught the problem and got it resolved.\nBring some cash. You must pay a deposit at check-in, or they absolutely won\u0026rsquo;t let you stay \u0026ndash; even bank cards weren\u0026rsquo;t accepted. And it was almost midnight.\nTravel tip: I later complained to headquarters, and the operations manager apologized, which I was satisfied with \u0026ndash; after all, I wasn\u0026rsquo;t trying to cause trouble, just felt wronged. So I still recommend Home Inn, with these suggestions: book and pay online in advance; bring some cash just in case; check the charges carefully; confirm any promotional offers.\nFood: Dining in Harbin has two somewhat unpleasant aspects: 1. Napkins aren\u0026rsquo;t free \u0026ndash; you need to buy them yourself; 2. You may need to share a table with strangers.\nI had spring pancakes:\nFor spring pancakes you need to share a table and buy your own napkins. But the taste was decent. I recommend Maomao Spring Pancakes and Laochang Spring Pancakes.\nHad hot cola:\nGinger cola \u0026ndash; available everywhere on Central Street. Be careful though, it spills easily. I saw 2-3 people spill theirs.\nHad rice cake hotpot:\nThe restaurant is in Ha Yi Bai (Harbin No.1 Department Store). This pot costs 59 RMB and comes with two drinks and kimchi. The staff is friendly, there\u0026rsquo;s wifi, and I highly recommend this place. It\u0026rsquo;s called Congee Story.\nHad desserts:\nThis dessert shop is quite famous \u0026ndash; it\u0026rsquo;s called \u0026ldquo;Pack Happiness\u0026rdquo; and is on Central Street. A bit pricey though. The taste is decent, suitable for artsy types. I did get a stomachache that evening \u0026ndash; not sure if it was related to their yogurt. I still recommend this place overall.\nHad Thai food:\nThai cuisine. I couldn\u0026rsquo;t quite get used to the taste. It\u0026rsquo;s in an alley off Central Street. Overall it\u0026rsquo;s OK, but if you\u0026rsquo;re not a big fan of Thai food, proceed with caution.\nTravel tip: Bring your own napkins, try to use group-buy deals, and avoid peak dining hours.\nSearch on Dianping: Maomao Spring Pancakes | Laochang Spring Pancakes | Pack Happiness | Impression Thai Southeast Asian Restaurant\nAttractions: Ice and Snow World: Just take the bus there \u0026ndash; don\u0026rsquo;t listen to tour salespeople. Bring your student ID.\nSaint Sophia Cathedral: Don\u0026rsquo;t go inside. Just enjoy the pigeons from outside.\n","date":"2015-01-28T03:17:57Z","permalink":"https://blog.coinidea.com/en/p/travel-guide-harbin/","title":"Travel Guide - Harbin"},{"content":"I recently had a requirement to batch convert Word files to HTML.\nFor a small number of Word files, you can simply use Word\u0026rsquo;s built-in \u0026ldquo;Save As\u0026rdquo; feature. But when dealing with a large number of Word files, it becomes quite complicated.\nAfter searching online, I found solutions in PHP, Python, Ruby, and C#. Among them, I found a tool called \u0026ldquo;Xunjiie Converter\u0026rdquo;, but it didn\u0026rsquo;t quite fit my needs, so I decided to write my own. Since Word is a Microsoft product, I figured C# might be the best choice for this task.\nI open-sourced a GUI-based solution on GitHub: https://github.com/hujiulin/ConvertWordToHTML [Currently single-threaded; will be converted to multi-threaded later].\nScreenshots of the running application:\nInitial program interface:\n\u0026ldquo;Open\u0026rdquo; to select an input folder containing Word documents:\n\u0026ldquo;SaveAs\u0026rdquo; to select an output folder:\nProgram finished running:\nInput and output results:\nProgram notes:\nDependencies: Windows OS, .NET Framework 3.5, Office Word\nWord\u0026rsquo;s \u0026ldquo;Save As HTML\u0026rdquo; offers several format options: single web page (mht), web page (htm), and filtered web page (htm). I chose the filtered HTML option, which converts all formulas to gif or jpg images. A properly filtered htm file won\u0026rsquo;t contain Microsoft\u0026rsquo;s messy formatting information.\nGitHub: https://github.com/hujiulin/ConvertWordToHTML\nDownload: http://devhu-github.stor.sinaapp.com/ConvertWordToHTML.rar\n2015-1-24 Update:\nRename solution and project to WordConverter; Add feature: convert word to PDF; ADD feature switch specified ext; The Word Converter tool now supports both HTML and PDF formats.\nUpdated GitHub link: https://github.com/hujiulin/WordConverter\nDownload: http://devhu-github.stor.sinaapp.com/WordConverter.rar\n","date":"2015-01-11T10:34:33Z","permalink":"https://blog.coinidea.com/en/p/batch-word-to-html--convertwordtohtml-update-word-converter-tool/","title":"Batch Word to HTML -- ConvertWordToHTML [Update: Word Converter Tool]"},{"content":"2014 felt both slow and fast for me. This year, one foot had already stepped into the working world, waiting for the other to follow. Here is a recap of the major events of my 2014 \u0026ndash; archiving the past and embracing a new future.\nRead some books.\n1.1 Wu Xiaobo\u0026rsquo;s \u0026ldquo;Great Defeats\u0026rdquo; complete collection\n1.2 Nanpai Sanshu\u0026rsquo;s \u0026ldquo;TheErta Tomb Notes\u0026rdquo;\n1.3 Went through \u0026ldquo;The Beauty of Programming\u0026rdquo; once\n1.4 Went through \u0026ldquo;Erta Programmer Interview Bible\u0026rdquo; once [for job hunting]\n1.5 Read parts of \u0026ldquo;Effective C++\u0026rdquo;\n1.6 Accepted all LeetCode problems.\nOn April 17th, I excitedly joined Microsoft Research Asia\u0026rsquo;s Innovation Engineering Group as an intern.\nThis was a rare opportunity in my life. I stumbled into a top-tier technology and research company (research institute), where I wrote code for half a year. The growth, both internal and external, had a profound impact on me. Before this, I thought I was a decent coder, but the two words I encountered most frequently there were: standards, and why.\nLooking back, the MSRA experience will influence my entire life. I sincerely thank my mentors: Genduan and Chaowa for their help.\nAs a Dev, I found my girlfriend in May 2014 \u0026ndash; what a joyful thing! I could finally do object-oriented programming.\nJob hunting phase\nI tossed and turned during that period. It reminded me of a blog post by Liang Bin, the operator of PennyJob: Rejected by a Hundred Companies.\nAlthough there were some offers here and there, the pressure was immense \u0026ndash; something only I could truly understand.\nOctober 8th, internship at Yuanfudao (Ape Question Bank).\nThis is a startup company \u0026ndash; a group of ambitious and talented people working together to do something cool and disruptive. My mentor was DevTang, a well-known iOS expert. What this company brought me was a refreshing experience. As a newcomer, being in a startup exposed me to so many things beyond technology yet closely related to it \u0026ndash; knowledge that will benefit me for life.\nTravel\nVisited Shidu. | Visited Beidaihe. | Visited Tianjin. | Visited Qingdao. | Visited Hong Kong.\nWhat\u0026rsquo;s next? When I resigned, my senior colleague asked me, what are you going to do next? Indeed, what am I going to do next? I couldn\u0026rsquo;t answer, but I hope my 2015 can include the following items:\nTravel\n1.1 Visit Harbin [Done] | 1.2 Visit Tibet | 1.3 Visit Yunnan [Done]\nConsistently maintain my personal blog for technical learning and sharing, and write high-quality posts [Done \u0026ndash; should be able to keep it up, though quality will improve gradually].\nWrite higher-quality code and contribute on GitHub. Hopefully one of my projects can get 100 stars.\nOpen-source a portal system based on ThinkPHP [Done, though not yet open-sourced].\nThink about my future and focus on mastering a specific technology.\nRead some proper books:\n6.1 Wu Jun\u0026rsquo;s \u0026ldquo;Civilization and Light\u0026rdquo;\n6.2 [Canadian] Malcolm Gladwell\u0026rsquo;s \u0026ldquo;David and Goliath\u0026rdquo;\n6.3 Finish \u0026ldquo;High Output Management\u0026rdquo; by Andy Grove\n6.4 Finish \u0026ldquo;Effective C++\u0026rdquo;\n6.5 \u0026ldquo;Predictably Irrational\u0026rdquo; [Done]\nStudy English properly and aim for independent international travel.\nRedo all LeetCode problems from scratch.\n","date":"2015-01-11T05:49:26Z","permalink":"https://blog.coinidea.com/en/p/year-end-review-my-2014/","title":"[Year-End Review] My 2014"},{"content":"As 2015 approaches, in order to become more focused and professional, I am migrating my blog from Sina:\nhttp://blog.sina.com.cn/u/1731162620\nto my personal site on SAE.\nMany thanks to:\nhttp://www.crifan.com/crifan_released_all/website/python/blogstowordpress/usage_example/\ncrifan\u0026rsquo;s blog migration tool.\n","date":"2014-12-19T02:42:52Z","permalink":"https://blog.coinidea.com/en/p/blog-migration/","title":"Blog Migration"}]